百度一下:基于连通性状态压缩的动态规划问题


#include <iostream>
using namespace std;

const int maxn = 12;
__int64 dp[maxn][maxn][1<<maxn];
int mp[12][12];

int main(){
	int T;
	scanf("%d",&T);
	for(int Case=1;Case<=T;Case++){
		int i,j,k,m,n;
		scanf("%d%d",&m,&n);
		for(i=1;i<=m;i++)
			for(j=1;j<=n;j++)
				scanf("%d",&mp[i][j]);
		memset(dp,0,sizeof(dp));
		dp[0][n][0]=1;
		for(i=1;i<=m;i++){
			for(j=0;j<(1<<n);j++)
				dp[i][0][j<<1]=dp[i-1][n][j];
			//把状态下拉一行
			//[i,n]的状态x和[i+1,0]的状态x是对应相同的
			//所以也避免了初始化的麻烦
			//上一行最右边的边格一定不与轮廓线重合
			//下一行最左边的边格一定不与轮廓线重合
			for(j=1;j<=n;j++){
				for(k=0;k<(1<<(n+1));k++){
					int p = 1<<j;
					//(i,j)轮廓段上插头
					int q = p>>1;
					//(i,j)轮廓段左插头
					bool x = p & k;
					bool y = q & k;
					if (mp[i][j]){//可以走
						dp[i][j][k]=dp[i][j-1][k^p^q];
						//必然有一个通路连接上一个格子的通路
						if (x!=y)
							dp[i][j][k]+=dp[i][j-1][k];
							//有一处新覆盖则有另外的一种情况
					}
					else{//为障碍格子
						if (x+y==0)//道路与轮廓线不相交
							dp[i][j][k]=dp[i][j-1][k];//和前面一个格子的状态数相同
						else
							dp[i][j][k]=0;
							//不合法,障碍格子不可能与轮廓线相交
					}
				}
			}
		}
		printf("Case %d: There are %I64d ways to eat the trees.\n",Case,dp[m][n][0]);
	}
	return 0;
}