題目大致意思就是給你1*2的矩形磚塊 讓你填充滿h*w的矩形區域 有多少種填充方法?hw的值小於12,
兩種解法:
1. 狀態壓縮dp
思路很簡單,對於每一個格子,我們考慮這個格子上面我們是豎向放磚塊還是橫向放磚塊,如果橫向放 我們就有橫着的兩個11表示,豎向放我們就用豎着的01表示,那麼每一行就可以表示爲一個狀態,在其中一行的時候,首先判斷當前行的狀態是否符合上一行的要求,即上一行爲0的地方這一行這個位置必須是1,上一行爲1的地方這一行這個位置就可以隨便,然後檢查一下當前行是否合法就可以了,合法指的是這一行與上一行的值按位與,得到的值的二進制中的連續1的個數都是偶數個。具體看代碼
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
#define LL long long
bool isRight[1<<13];
bool isOk(int s)
{
int cnt = 0;
while(s)
{
if(s&1)
{
cnt++;
}
else
{
if(cnt&1)return false;
cnt = 0;
}
s>>=1;
}
if(cnt&1)return false;
return true;
}
int main()
{
memset(isRight,false,sizeof(isRight));
for(int i = 0;i<1<<13;i++)
{
if(isOk(i))
{
isRight[i] = true;
}
}
int h,w;
while(scanf("%d%d",&h,&w) && h && w)
{
LL dp[15][1<<13];
memset(dp,0,sizeof(dp));
for(int i = 0;i<(1<<w);i++)
{
if(isRight[i])
{
dp[0][i] = 1;
}
}
for(int i = 1;i<h;i++)
{
for(int j = 0;j<(1<<w);j++)
{
for(int k = 0;k<(1<<w);k++)
{
int nk = ((1<<w)-1)^k;
if((nk&j) != nk)continue;
// 上面兩行代碼是判斷當前狀態是否符合上面一行的要求 用位運算 上一行取反 然後異或當前行判斷是否相等 判斷
if(isRight[j&k])
{
dp[i][j] += dp[i-1][k];
}
}
}
}
//cout << isRight[7] << endl;
printf("%lld\n",dp[h-1][(1<<w)-1]);
}
return 0;
}
- 輪廓線動態規劃
這裏有一個非常好的題解
簡單的說一下自己的理解吧,輪廓線的的轉移類似一個蛇在圖上移動,每次用下一個格子和上一個輪廓線(蛇)來轉移,在新的格子有兩種放放法,例如以題解中的o格 可以放磚在K4O上 即上放,或者k0O即左放
代碼:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
#define LL long long
int main()
{
int w,h;
while(scanf("%d%d",&h,&w) && w && h)
{
LL dp[15][1<<13];
memset(dp,0,sizeof(dp));
dp[0][(1<<w)-1] = 1;
int cur = 0;
for(int i = 0;i<h;i++)
{
for(int j = 0;j<w;j++)
{
for(int k = 0;k<(1<<w);k++)
{
// 不放 直接左移 但是保證上一個輪廓線首位爲1
if(k & (1<<w-1))
dp[!cur][(k<<1)&(1<<w)-1] += dp[cur][k];
// 上放 上一個輪廓線首位爲0不然放不了
if(i && !((1<<(w-1))&k))
dp[!cur][(k<<1)|1] += dp[cur][k];
// 左放 保證上一個 輪廓線尾部爲0 然後左放
if(j && !(k&1) && (k & (1<<w-1)))
{
int id = (((k|1)<<1)|1) & (1<<w)-1;
dp[!cur][id] += dp[cur][k];
}
}
memset(dp[cur],0,sizeof(dp[cur]));
cur = !cur;
}
}
printf("%lld\n",dp[cur][(1<<w)-1]);
}
return 0;
}
兩個代碼時間差別非常大 狀態壓縮用了579ms 輪廓線用了79ms