CodeForces 11D 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.
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 the number of cycles in the given graph.
4 6 1 2 1 3 1 4 2 3 2 4 3 4
7
The example graph is a clique and contains four cycles of length 3 and three cycles of length 4.
题意:
求一个图中(节点个数小于20)长度大于等于三的哈密顿路径数目。
思路:
点数不多,类似TSP,用状压dp解决。
dp[i][j]表示状态为i时。以j结尾的路径条数。
假设下一个点能回到已经走过的一个点中,那么就是一个回路了。
为了避免反复计算,回到的点为走过的最小的点。(这是一个优化,少了枚举最小点这个循环)
长度为2的哈密顿路径会计算到,能够不做处理,最后减去边的条数就可以,每一个环会算两遍,最后要除以2.
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #define maxn 205 #define MAXN 100005 #define mod 1000000009 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-6 typedef long long ll; using namespace std; ll n,m,ans,flag,cnt,tot; ll mp[20][20],dp[1<<19][19]; int first(int s) { for(int i=0;i<n;i++) { if(s&(1<<i)) return i; } } void solve() { ll i,j,t,k,p,u,v,s; ans=0; tot=(1<<n)-1; memset(dp,0,sizeof(dp)); for(i=0;i<n;i++) { dp[1<<i][i]=1; } for(i=1; i<=tot; i++) { for(j=0; j<n; j++) { if(dp[i][j]==0) continue ; p=first(i); for(k=p; k<n; k++) { if(j==k||mp[j][k]==0) continue ; if(i&(1<<k)) { if(k==p) ans+=dp[i][j]; } else { s=i|(1<<k); dp[s][k]+=dp[i][j]; } } } } ans-=m; ans/=2; printf("%I64d\n",ans); } int main() { ll i,j,t; while(~scanf("%I64d%I64d",&n,&m)) { memset(mp,0,sizeof(mp)); ll u,v; for(i=1; i<=m; i++) { scanf("%I64d%I64d",&u,&v); u--,v--; mp[u][v]=mp[v][u]=1; } solve(); } return 0; }