POJ 2411 压缩状态DP

这个题目非常赞! 给定一个矩形,要求用1*2 的格子进行覆盖,有多少种覆盖方法呢?

dp[i][j] 当状态为j,且第i行已经完全铺满的情况下的种类数有多少种?j中1表示占了,0表示没有被占。

很显然,当每行被放了之后,有一些状态是不可能的,我们这里用1 表示竖着放,0表示横着放。 所以两个0 要相邻,这是程序中的s。

我们每一状态转移,枚举每一个可能的状态,我们希望dp[i][j] 中的j呈现出s[k] 的状态,依次来进行状态转移。

#include <iostream>

#include <vector>

#include <cstring>

using namespace std;



vector<int> s;  // possible state

long long dp[13][1<<12];  // dp[i][j]  the number of (row i state j)



int main()

{

    //freopen("1.txt","r",stdin);

    int M,N;

    while(cin>>M>>N && M!=0 && N!=0)

    {

        s.clear();

        if(M*N%2) {cout<<0<<endl; continue;}

        memset(dp,0,sizeof(dp));

        // 0-0 pair

        for(int tag = 0; tag < (1<<N); tag++)

        {

            for(int i=0; i<N; )

            {

                if(tag & (1<<i)) i++;

                else

                {

                    if( i+1< N && !(tag&(1<<(i+1)))) i+=2;

                    else break;

                }

                if(i== N) s.push_back(tag);

            }

        }

        for(int i=0; i<s.size(); i++) dp[0][s[i]] = 1;

        for(int step = 1; step< M; step++)

        {

            for(int tag = 0; tag < (1<<N); tag++)

            {

                for(int i=0; i<s.size(); i++)

                {

                    if((tag & s[i]) != tag) continue;

                    dp[step][tag^ s[i]] += dp[step-1][tag];

                }

            }

        }

        cout<<dp[M-1][0]<<endl;

    }

    return 0;

}

你可能感兴趣的:(poj)