POJ 1321 棋盘问题(DFS & 状压DP)

时间:2024-04-04 23:33:22

用DFS写当然很简单了,8!的复杂度,16MS搞定。

在Discuss里看到有同学用状态压缩DP来写,就学习了一下,果然很精妙呀。

状态转移分两种,当前行不加棋子,和加棋子。dp[i][j]中,i代表行数,j代表当前行棋子的状态。j的二进制中,1代表有旗子,0代表无棋子。

贴代码~状压DP果然快一点。

#include <cstdio>
#include <cstring> int n,k,count;
bool mp[][];
int num[];
int dp[][]; int main()
{
// freopen("in.txt","r",stdin); for(int i=;i<;i++)
{
int tmp=i;
while(tmp)
{
if(tmp&)
num[i]++;
tmp>>=;
}
} while(~scanf("%d%d",&n,&k) && n!=- && k!=-)
{
char str[];
for(int i=;i<=n;i++)
{
scanf("%s",str+);
for(int l=;l<=n;l++)
{
if(str[l]=='#')
mp[i][l]=true;
else
mp[i][l]=false;
}
} int status=<<n; memset(dp,,sizeof(dp));
dp[][]=;
for(int i=;i<=n;i++)
{
for(int j=;j<status;j++) if(num[j]<=k)
{
dp[i][j]+=dp[i-][j];
for(int l=;l<=n;l++) if(mp[i][l] && (j&(<<(l-)))==)
{
dp[i][(j|(<<(l-)))]+=dp[i-][j];
}
}
} int ans=;
for(int i=;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[][];
bool col[]; void DFS(int x,int rest)
{
if(rest==)
{
count++;
return;
}
if(x>n)
return;
for(int i=;i<=n;i++) if(!col[i] && mp[x][i])
{
col[i]=true;
DFS(x+,rest-);
col[i]=false;
}
if(rest+x<=n)
DFS(x+,rest);
} int main()
{
// freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&k) && n!=- && k!=-)
{
memset(col,,sizeof(col));
char str[];
for(int i=;i<=n;i++)
{
scanf("%s",str+);
for(int k=;k<=n;k++)
{
if(str[k]=='#')
mp[i][k]=true;
else
mp[i][k]=false;
}
} count=;
DFS(,k);
printf("%d\n",count);
}
}