题目: http://poj.org/problem?id=1321
题目 :给定一个棋盘n*n,要求放m颗棋子上去,要求 每一行每一列只能有一个棋子,问有多少中放置方法?
解题:状态:dp[i][j][k]; 表示 前i行,状态为j,容纳人数为k的情况数
边界:dp[1][0][0] = 1 ; dp[1][第一行的每一个状态...][1] = 1;
转移:因为n最大是8,数据较小,所以枚举前i行状态的时候,我从0枚举到1<<n
枚举到第i行
1. 第i行一个棋子都不放,即当前行状态为s = 0 ,dp[i][0..(1<<n)][0..总人数] = dp[i-1][0..(1<<n)][0..总人数];
2. 枚举前i-1的所有状态 0~1<<n,如preState和当前行的状态不冲突,则转移:
if(preState & nowState == 0 ) dp[i][preState|nowState][people+1] = dp[i-1][preState][people]; people = 0~总人数-1
#include<stdio.h>
#include<memory.h>
const int maxn = (1<<8);
int dp[8+1][maxn][8+1];//前i行,状态为j,容纳人数为k的情况数
char map[8+1][8+1];
int line[8+1][8+1];
int cnt[8+1];
int n,m;
int main()
{
while(true)
{
scanf("%d%d",&n,&m);
if(n==-1 && m==-1) break;
for(int i=1;i<=n;i++)
{
scanf("%s",map[i]);
line[i][0] = 0;
cnt[i] = 1; //第一种是这一行一个都不放
for(int j=0;j<n;j++)
{
if(map[i][j]=='#')
{
line[i][cnt[i]++] = (1<<j);
}
}
}
memset(dp,0,sizeof(dp));
//边界,第一行
dp[1][0][0] = 1; //
for(int i=1;i<cnt[1];i++)
{
dp[1][line[1][i]][1] = 1; //第一行放一个
}
for(int i=2;i<=n;i++)//第i行
{
for(int k=0;k<(1<<n);k++)//这一行一个都不放
{
for(int l=0;l<=m;l++) //前i行容纳的人数
{
dp[i][k][l] += dp[i-1][k][l];
}
}
for(int j=1;j<cnt[i];j++)//当前行的放1个
{
int state = line[i][j];
for(int k=0;k<(1<<n);k++)//前i-1行的状态
{
if(state & k) continue;
for(int l=0;l<=m-1;l++) //前i行容纳的人数
{
dp[i][state|k][l+1] += dp[i-1][k][l];
}
}
}
}
int rs = 0;
for(int j=0;j<(1<<n);j++)
{
rs = rs + dp[n][j][m];
}
printf("%d\n",rs);
}
return 0;
}//0ms
加油吧,渣科