poj 1321 棋盘问题 (状态压缩DP)
状态方程为dp[i][s]=dp[i-1][s']+dp[i-1][s] (sum[s]<i)
或dp[i][s]=dp[i-1][s'] (sum[s]==i)
如果s与base矛盾,则s'必须含有s与base矛盾的项。
(其中i为第几行,s为状态,s'为是的子状态,base数组记录棋盘状态('.'为1,'#'为0),sum[s]记录s中1的个数)
View Code
#include<iostream> #include<cstdio> #include<string.h> using namespace std; int n,m; int base[10],dp[10][300]; int state[300],sum[300]; int main() { //freopen("test.txt","r",stdin); while(~scanf("%d%d",&n,&m)) { if(n==-1&&m==-1) return 0; int i,j,t,p,k,q; memset(base,0,sizeof(base)); memset(dp,0,sizeof(dp)); memset(state,0,sizeof(state)); memset(sum,0,sizeof(sum)); char str[10]; for(i=1;i<=n;i++) { scanf("%s",str); for(j=0;j<n;j++) { if(str[j]=='.') base[i]+=(1<<j); } } int num=0; for(i=0;i<(1<<n);i++) { k=i; while(k) { sum[num]+=1&k; k>>=1; } state[num++]=i; } dp[0][0]=1; for(i=1;i<=n;i++) { for(j=0;j<num;j++) { if(sum[j]>i) continue; if(base[i]&state[j]) //当前状态与base有矛盾 { p=base[i]&state[j]; t=0; q=p; while(p) { if(1&p) t++; p>>=1; } if(t==n) continue; for(t=0;t<n;t++) { if(j&(1<<t)) { k=1<<t; if(k&q) continue; k=j-k; dp[i][j]+=dp[i-1][k]; } } if(sum[j]<i) dp[i][j]+=dp[i-1][j]; } else { for(t=0;t<n;t++) { if(j&(1<<t)) { k=1<<t; k=j-k; dp[i][j]+=dp[i-1][k]; } } if(sum[j]<i) dp[i][j]+=dp[i-1][j]; } } } int ans=0; for(i=0;i<num;i++) { if(sum[i]==m) ans+=dp[n][i]; } printf("%d\n",ans); } return 0; }