POJ 1321 棋盘问题

来源:互联网 发布:北京机房网络质量排行 编辑:程序博客网 时间:2024/06/05 20:12
#include<stdio.h>#include<string.h>int check(int a,int m){    int b=0;    while(a>0)    {        if(a&1)            b++;        a>>=1;    }    if(b==m)        return 1;    return 0;}int main(){    int n,m,dp[(1<<8)+5][10],Map1[10],s[1000],len;//dp[i][j]定义状态为在j行的状态为i    char Map[10][10];    while(scanf("%d%d",&n,&m)!=EOF)    {        if(n==0||m==0)        {            printf("0\n");            continue;        }        if(n==-1&&m==-1)            break;        for(int i=0; i<n; i++)            scanf("%s",Map[i]);        memset(Map1,0,sizeof(Map1));        for(int i=0; i<n; i++)//压缩地图        {            for(int j=0; j<n; j++)                if(Map[i][j]=='.')                    Map1[i]=Map1[i]|(1<<(n-1-j));        }        len=0;        for(int i=0; i<(1<<n); i++)//把所有的有m个1的状态存到一个数组里            if(check(i,m))                s[len++]=i;        memset(dp,0,sizeof(dp));        for(int j=0;j<n;j++)//把所有为1个1的都都初始化为1,由这些点这些为只有一个1的状态去扩展,所以这个能用dp的本质是算出来所有一个情况,然后扩展成两个的情况,慢慢扩展,所以最后求一下题目要求的m的所有状态的和就行了        {            for(int i=1; i<(1<<n); i=(i<<1))                if((Map1[j]&i)==0)                    dp[i][j]=1;        }        for(int i=1; i<n; i++)//枚举行        {            for(int j=0; j<(1<<n); j=j==0?1:j<<1)//直接枚举当前行的状态是0,1,2,4,8.(也就是只有一个1)            {                if((j&Map1[i])==0)//判断是否和地图矛盾                    for(int k=0; k<(1<<n); k++)//枚举上一行的状态                        if((k&j)==0)//判断两个状态是否矛盾,当j==0的时候表示当前行不放,当j不等于0的时候是放在那,所以当j放一个位置的时候无论扩展到那个一个状态,都等于1*dp[k][i-1]中情况所以直接加上就行                            dp[k|j][i]+=dp[k][i-1];            }        }        for(int i=0;i<n;i++)        {            for(int j=0;j<(1<<n);j++)                printf("%d ",dp[j][i]);            puts("");        }        int ans=0;        for(int i=0; i<len; i++)                ans+=dp[s[i]][n-1];        printf("%d\n",ans);    }    return 0;}/*4 3#..##.#...#.#.##5 4#..#.#.#....#..#.##..####3 3#########*//*5 4#.#.##...#..###..###*/

0 0