poj 1321 棋盘问题 (状态压缩DP)

状态方程为dp[i][s]=dp[i-1][s']+dp[i-1][s] (sum[s]<i)

或dp[i][s]=dp[i-1][s'] (sum[s]==i)

如果s与base矛盾,则s'必须含有s与base矛盾的项。

(其中i为第几行,s为状态,s'为是的子状态,base数组记录棋盘状态('.'为1,'#'为0),sum[s]记录s中1的个数)

View Code
#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
int n,m;
int base[10],dp[10][300];
int state[300],sum[300];
int main()
{
    //freopen("test.txt","r",stdin);
    while(~scanf("%d%d",&n,&m))
    {
        if(n==-1&&m==-1)
        return 0;
        int i,j,t,p,k,q;
        memset(base,0,sizeof(base));
        memset(dp,0,sizeof(dp));
        memset(state,0,sizeof(state));
        memset(sum,0,sizeof(sum));
        char str[10];
        for(i=1;i<=n;i++)
        {
            scanf("%s",str);
            for(j=0;j<n;j++)
            {
                if(str[j]=='.')
                base[i]+=(1<<j);
            }
        }
        int num=0;
        for(i=0;i<(1<<n);i++)
        {
            k=i;
            while(k)
            {
                sum[num]+=1&k;
                k>>=1;
            }
            state[num++]=i;
        }
        dp[0][0]=1;
        for(i=1;i<=n;i++)
        {
            for(j=0;j<num;j++)
            {
               if(sum[j]>i) continue;
               if(base[i]&state[j]) //当前状态与base有矛盾
               {
                   p=base[i]&state[j]; 
                   t=0;
                   q=p;
                   while(p)
                   {
                       if(1&p)
                       t++;
                       p>>=1;
                   }
                   if(t==n) continue;
                   for(t=0;t<n;t++)
                   {
                       if(j&(1<<t))
                       {
                           k=1<<t;
                           if(k&q) continue; 
                           k=j-k;
                           dp[i][j]+=dp[i-1][k];
                       }
                   }
                   if(sum[j]<i) dp[i][j]+=dp[i-1][j];
               }
               else
               {
                   for(t=0;t<n;t++)
                   {
                       if(j&(1<<t))
                       {
                           k=1<<t;
                           k=j-k;
                           dp[i][j]+=dp[i-1][k];
                       }
                   }
                   if(sum[j]<i) dp[i][j]+=dp[i-1][j];
               }
            }
        }
        int ans=0;
        for(i=0;i<num;i++)
        {
            if(sum[i]==m)
            ans+=dp[n][i];
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2013-04-25 22:15  longlongago  Views(178)  Comments(0Edit  收藏  举报