設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<