POJ 1321 棋盘问题(DFS & 状压DP)
用DFS写当然很简单了,8!的复杂度,16MS搞定。
在Discuss里看到有同学用状态压缩DP来写,就学习了一下,果然很精妙呀。
状态转移分两种,当前行不加棋子,和加棋子。dp[i][j]中,i代表行数,j代表当前行棋子的状态。j的二进制中,1代表有旗子,0代表无棋子。
贴代码~状压DP果然快一点。
#include <cstdio> #include <cstring> int n,k,count; bool mp[10][10]; int num[256]; int dp[9][256]; int main() { // freopen("in.txt","r",stdin); for(int i=1;i<256;i++) { int tmp=i; while(tmp) { if(tmp&1) num[i]++; tmp>>=1; } } while(~scanf("%d%d",&n,&k) && n!=-1 && k!=-1) { char str[20]; for(int i=1;i<=n;i++) { scanf("%s",str+1); for(int l=1;l<=n;l++) { if(str[l]=='#') mp[i][l]=true; else mp[i][l]=false; } } int status=1<<n; memset(dp,0,sizeof(dp)); dp[0][0]=1; for(int i=1;i<=n;i++) { for(int j=0;j<status;j++) if(num[j]<=k) { dp[i][j]+=dp[i-1][j]; for(int l=1;l<=n;l++) if(mp[i][l] && (j&(1<<(l-1)))==0) { dp[i][(j|(1<<(l-1)))]+=dp[i-1][j]; } } } int ans=0; for(int i=0;i<status;i++) if(num[i]==k) ans+=dp[n][i]; printf("%d\n",ans); } }
还有传统的DFS……
#include <cstdio> #include <cstring> int n,k,count; bool mp[10][10]; bool col[10]; void DFS(int x,int rest) { if(rest==0) { count++; return; } if(x>n) return; for(int i=1;i<=n;i++) if(!col[i] && mp[x][i]) { col[i]=true; DFS(x+1,rest-1); col[i]=false; } if(rest+x<=n) DFS(x+1,rest); } int main() { // freopen("in.txt","r",stdin); while(~scanf("%d%d",&n,&k) && n!=-1 && k!=-1) { memset(col,0,sizeof(col)); char str[20]; for(int i=1;i<=n;i++) { scanf("%s",str+1); for(int k=1;k<=n;k++) { if(str[k]=='#') mp[i][k]=true; else mp[i][k]=false; } } count=0; DFS(1,k); printf("%d\n",count); } }