poj 2411 状态压缩dp

思路:将每一行看做一个二进制位,那么所有的合法状态为相邻为1的个数一定要为偶数个。这样就可以先把所有的合法状态找到。由于没一层的合法状态都是一样的,那么可以用一个数组保存。由第i-1行到第i行的状态转移是dp[i][now|num[j]]+=dp[i-1][k],其中now为(1<<m)-1-k;也就是把k中含有0的变1,1边0。k为第i-1行的所有二进制状态,转移条件是k&num[j]==num[j]。唯一注意的是,最后一行的条件是k^num[j]==0.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Maxn 13
#define inf 0x7fffffff
using namespace std;
__int64 dp[Maxn][1<<Maxn];
int num[1<<Maxn],cnt1,cnt2,graphic[Maxn],co,n,m;
void dfs(int j,int f)
{
    int i;
    if(j==m)
    {
        int sum=0;
        if(f)
            graphic[j]=1;
        else
            graphic[j]=0;
        for(i=m;i>=1;i--)
            sum+=graphic[i]*(1<<(m-i));
        num[++cnt2]=sum;
        return ;
    }
    if(!f)
    {
        graphic[j]=0;
        dfs(j+1,0);
        graphic[j]=1;
        dfs(j+1,1);
    }
    else
    {
        graphic[j]=1;
        dfs(j+1,0);
    }
}
int main()
{
    int i,j,k;
    while(scanf("%d%d",&n,&m)!=EOF,n||m)
    {
        if((n*m)%2)
        {
            printf("0
");
            continue;
        }
        if(n==1)
        {
            printf("1
");
            continue;
        }
        memset(dp,0,sizeof(dp));
        graphic[0]=0;
        cnt2=0;
        dfs(1,0);
        for(i=1;i<=cnt2;i++)
            dp[1][num[i]]=1;
        int temp=1<<m;
        temp--;
        for(i=2;i<=n-1;i++)
        {
            for(j=1;j<=cnt2;j++)
            {
                for(k=0;k<=temp;k++)
                {
                    if((k&num[j])==num[j])
                    {
                        int now=temp-k;
                        dp[i][now|num[j]]+=dp[i-1][k];
                    }
                }
            }
        }
        __int64 ans=0;
        for(j=1;j<=cnt2;j++)
        {
            for(k=0;k<=temp;k++)
            {
                if((k^num[j])==0)
                    ans+=dp[i-1][k];
            }
        }
        printf("%I64d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wangfang20/p/3240466.html