天天看点

Codeforces Beta Round #11 D. A Simple Task(状压DP)

Given a simple graph, output the number of simple cycles in it. A simple cycle is a cycle with no repeated vertices or edges.

Input
The first line of input contains two integers n and m (1 ≤ n ≤ 19, 0 ≤ m) – respectively the number of vertices and edges of the graph. Each of the subsequent m lines contains two integers a and b, (1 ≤ a, b ≤ n, a ≠ b) indicating that vertices a and b are connected by an undirected edge. There is no more than one edge connecting any pair of vertices.

Output
Output the number of cycles in the given graph.

Examples
input
4 6
1 2
1 3
1 4
2 3
2 4
3 4
output
7
Note
The example graph is a clique and contains four cycles of length 3 and three cycles of length 4.
           

分析:求简单环个数,n很小,但是爆搜是不行的。。因为结果是阶乘级别的,考虑状压dp,f[i][s][t]表示当前链中点的集合为i,起点为s终点为t的所有方案数,因为s,t必定属于i,而且一个简单环有多重表示方法,所以我们考虑精简状态,f[i][t]表示起点s 为 i 中编号最小点,终点为t的所有链方案数,最后如果edg(s,t)存在就将f[i][t]记入答案,因为环上每点有两个相邻点,所以最后答案要除以二。

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<queue>
#define INF 2147483640
#define eps 1e-9
#define MAXN 0x3f
#define N 20
using namespace std;
int n,m,u,v,fh[1<<19];
unsigned long long ans,dp[1<<19][N];
bool edg[N][N];
int f(int x)
{
	return 1<<(x-1);
}
int main()
{
	cin>>n>>m;
	for(int i = 1;i <= n;i++) fh[f(i)] = i;
	for(int i = 1;i <= m;i++)
	{
		cin>>u>>v;
		edg[u][v] = edg[v][u] = true;
	}
	for(int i = 1;i <= (1<<n)-1;i++)
	 for(int t = fh[i & (-i)] + 1;t <= n;t++)
	  if(f(t) & i)
	  {
	     int s = fh[i & (-i)],sta = i - f(t) - f(s);
	     if(!sta)
	     {
	     	dp[i][t] = edg[s][t];
	     	continue;
		 }
		 for(int j = sta;j;j -= j & (-j))
		  if(edg[fh[j & (-j)]][t])
		   dp[i][t] += dp[i - f(t)][fh[j & (-j)]]; 
		 if(edg[s][t]) ans += dp[i][t];
	  }
	cout<<ans/2<<endl;
}
           

继续阅读