POJ 2411-狀壓dp

設dp[i][state]爲貼到第i行,前一行的狀態爲state時的方法數,枚舉兩層的狀態來轉移,先判斷轉移是否合法(即保證上一層是貼滿的)。

鏈接付不上去,臥槽。。

/****************************
* author:crazy_石頭
* date:2014/04/29
* time:219 ms
* algorithm:狀壓dp 
* Pro:POJ 2411
***************************/
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <string>
#include <queue>
#include <vector>
#include <climits>
 
using namespace std;
 
#define INF INT_MAX
#define eps 1e-8
#define A system("pause")
#define rep(i,h,n) for(int i=(h);i<=(n);i++)
#define ms(a,b) memset((a),(b),sizeof(a))
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define LL long long
const int maxn=13;
const int maxm=30;
LL dp[maxn][1<<maxn];
int n,m;
inline int judge(int now,int next) 
{//next爲下一行的狀態; 
       for(int i=0;i<m;i++)
       {
           int a=now&(1<<i);
           int b=next&(1<<i);
           if(a==0){ if(b==0) return 0;}
           else if(b)
           {
                i++;
                if(i==m) return 0;
                if((now&(1<<i))==0) return 0;
                if((next&(1<<i))==0) return 0;
           }
       }
       return 1;
}  

int main()
{
      while(cin>>n>>m)
      {
         if(n+m==0) break;
         if((n*m)&1) 
         {
             cout<<0<<endl;
             continue;
         }
         if(n<m) std::swap(n,m);
         ms(dp,0);
         int all=(1<<m)-1;
         dp[0][all]=1;
         for(int i = 0; i < n; i ++)
         {
            for(int now = 0; now <= all; now ++) 
            if(dp[i][now]) 
            {
                for(int next = 0; next<= all; next ++) 
                if(judge(now,next)) 
                {
                    dp[i+1][next] += dp[i][now];
                }
            }
        }
        cout<<dp[n][all]<<endl;
      }
      return 0;
}



dfs的話,中午看了一下,其實這種做法比較好理解,直接往過搜就行。

方程表示爲:dp[i][j]+=dp[i-1][k](能夠從上一行的狀態k轉移到當前狀態j)。我們需要枚舉出符合要求的狀態j和k,如果第i-1行p列沒有放,那麼第i行的p列肯定需要放置一個豎塊,如果第i-1行p列放了,那麼i行的p列可以不用放,如果第i-1行的p列和p+1列都放了,那麼我們可以在第i行的p列和p+1列橫着放置一個磚塊。


我們用dfs實現,那麼上述三種情況可以分別表示爲


dfs(step+1,s1<<1|1,s2<<1,line); 豎放
dfs(step+1,s1<<1,s2<<1|1,line);不放
dfs(step+2,s1<<2|3,s2<<2|3,line);橫放

代碼也是分分鐘敲出來:

#include 
#include 
#include 
#include 
using namespace std;
#define MAXN 15
typedef long long LL;
LL dp[MAXN][1<


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章