最近學了狀壓dp,把之前未解決的題目捋一捋。
這是之前的一道題
今天蒜頭君裝修新家,給家裡買了一種 1×2或2×1 的長方形(如圖1)新瓷磚。蒜頭君是個懂得審美的人,畢竟人生除了金錢,還有詩和遠方。
這個時候蒜頭君就在想,這種長方形的瓷磚鋪到乙個 10×10 10 \times 10 10×10 的地面上有多少種方案?(如圖2:是 4×44 \times 44×4 地面的一種方案)
圖1:
圖2:
問10×10的地面用2×1的瓷磚鋪能有多少方案。
我們直接一般化,有n×m的地面,求有多少種方案。
但是我也會講解一點。
思路還是老思路,由前一行來推下一行。
首先我們選好狀態的表示方法,1表示影響下一行,0表示不影響,為什麼這樣表示,因為這樣可以很好的表示橫著鋪和豎著鋪兩種方案,1就表示這個格仔是豎著鋪的第一行,0表示這個格仔可能是橫著鋪的中間乙個,也可能是豎著鋪的第二個格仔,反正0就不影響,下一行不用考慮。
這是別人附的一張圖,它是用0表示影響的,1表示不影響。
然後了解了狀態表示之後,我們就可以推導了。
和很多題一樣,對於新的一種狀態,我們逐位考慮。
分兩大類
①某一位是0。
這個上面也說過,它不影響下一行,可能是橫這鋪的,也可能是豎著鋪的其中的第二個。
對於橫著鋪,我們要考慮旁邊的格仔是不是0,如果不是,直接就false了,這個狀態不成立
對於豎著鋪,首先我們判定它是豎著鋪的方法是前一行的同一位是1,當前行的這一位是0,只有滿足這兩個條件就ok了
②第二類是某一位是1
這就說明它一定豎著鋪,而且是第乙個格仔。
那麼上一行就不能是1,就這乙個條件。
由以上的思路,我們可以寫出關鍵的函式。
下面是**
#include #include #include#include#include#include #include #define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define fork(l,r) for( int k = l ; k <= r ; k++ )
#define lef rt<<1
#define rig rt<<1|1
#define mid (l+r)>>1
#define mem(a,val) memset(a,val,sizeof a)
typedef long long ll;
using namespace std;
int r,c;
const int maxn = 1<<12;
ll dp[13][maxn];
bool initcheck( int x ) //檢查第一行的狀態
cnt--;
}return true;
}bool judge( int cur,int pre )
else
}cnt--;
}return true;
}int main()
cnt--;
}return true;
}bool judge( int cur,int pre )
else
}cnt--;
}return true;
}int main()
{ while( scanf("%d %d",&r,&c) == 2 && r )
{if( c > r )
swap(c,r);
mem(dp,0);
mem(vis,false);
fori(1,r)
v[i].clear();
int right = 1那麼對於前面的那道題,直接輸入10 10就可以得到答案了。
哎,當時還是太菜
鋪瓷磚 狀壓dp經典問題
給出 n m的矩形方塊,可以往上面鋪1 2的磚塊,問鋪滿這個方塊的方案有多少種。磚塊可以豎鋪和橫鋪,豎鋪的話會影響到下一行,橫鋪的話不會影響到下一行,這裡我們令1 表示該方塊不會影響下一行,0 表示該方塊會影響下一行。條件一 考慮 i.j 這一格,如果 i 1,j 上是0,那說明 i 1,j 是豎鋪...
狀態壓縮dp(鋪瓷磚問題)
今天蒜頭君裝修新家,給家裡買了一種 1 times 21 2的長方形 如圖1 新瓷磚。蒜頭君是個懂得審美的人,畢竟人生除了金錢,還有詩和遠方。這個時候蒜頭君就在想,這種長方形的瓷磚鋪到乙個 10 times 1010 10 的地面上有多少種方案?如圖2 是 4 times 44 4 地面的一種方案 ...
狀壓dp 玉公尺田 狀壓dp
相關 強相關 327.玉公尺田 狀壓dp 小國王 狀壓dp 是井字形,本題是十字形。思路 狀態計算 時間複雜度 n 2 n 2n o n 22n 12 2 24n 2 n 2 n o n2 12 2 n 2n 2 n o n22n 12 224 看著妥妥超時,但是裡面合法狀態很少 依舊可以過 在此,...