poj1321 棋盘问题(状态压缩)

题目: 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

加油吧,渣科

猜你喜欢

转载自blog.csdn.net/zark721/article/details/81149724
今日推荐