插头DP基础题的样子。。。输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物。输出哈密顿回路(可以多回路)方案数。。。
看了个ppt,画了下图。。。感觉还是挺有效的。。。
参考http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710343.html
以及推荐cd琦的论文ppthttp://wenku.baidu.com/view/4fe4ac659b6648d7c1c74633.html
向中学生学习~~
感觉以后可能还会要看这篇日志。所以特意加了较多的注释。。。观客可以看注释=。=推荐画示意图。。。。
复杂度O(n*m*2^(m+1))
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <string> 7 #include <vector> 8 #include <queue> 9 #include <set> 10 using namespace std; 11 12 #define ll long long 13 #define inf 0x3f3f3f3f 14 #define eps 1e-8 15 16 int a[12][12]; 17 ll dp[12][12][1<<12]; 18 int main(){ 19 int t,ca=0; 20 scanf("%d",&t); 21 while(t--){ 22 int n,m; 23 scanf("%d%d",&n,&m); 24 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)scanf("%d",&a[i][j]); 25 memset(dp,0,sizeof(dp)); 26 dp[1][0][0]=1; 27 int ma=(1<<(m+1)); 28 for(int i=1;i<=n;++i){ 29 for(int j=1;j<=m;++j){ 30 for(int k=0;k<ma;++k){ 31 int d=1<<(j-1),r=1<<j; 32 if(a[i][j]){// 该位置无障碍 33 if( ( (k&d)&&(k&r) ) || ( (~k&d)&&(~k&r)) )// 右插下插同时有或同时无,必须翻转 34 dp[i][j][k]=dp[i][j-1][k^d^r]; 35 else // 右插下插只有一个,可翻转可不翻转 36 dp[i][j][k]=dp[i][j-1][k]+dp[i][j-1][k^d^r]; 37 } 38 else {// 该位置有障碍 39 if((k&d)==0&&(k&r)==0)// 没有右插没有下插,则方案数跟随 40 dp[i][j][k]=dp[i][j-1][k]; 41 } 42 } 43 } 44 if(i+1<=11) 45 for(int k=0;k<(1<<m);++k)// 换行去掉上一行的右插,下一行的开头没有进来的左插,请画图 46 dp[i+1][0][k<<1]=dp[i][m][k]; 47 } 48 printf("Case %d: There are %I64d ways to eat the trees.\n",++ca,dp[n][m][0]); 49 } 50 return 0; 51 }