HihoCoder第九周 狀態壓縮 二 與POJ2411總結
阿新 • • 發佈:2019-01-31
在此我向各位博友求助,特別想知道除了HihoCoder上面的結果要對1e9+7取餘之外,這兩道題還有什麼其他的問題,都是骨牌覆蓋問題,都是狀態壓縮+dp,為什麼我能過poj2411的程式過不了HihoCoder,還不是其他諸如TimeLimited,而是Wrong Answer,這個問題我想了很久,還是不知道是怎麼回事,如果有神通廣大的博友知道答案,希望你能告訴我。順便說一下,HihoCoder給的那個hint只看懂了一部分遞推的公式,其中滿足的那個條件還是不懂。
兩個題目的連線地址:
骨牌覆蓋問題我想了很久很久,我自己也知道對於每一個位置上的骨牌來說,有三種可能,有可能是上樓的骨牌,有可能是下樓的骨牌,也有可能是同樓層的骨牌。但當時我思考的時候,就在想,比方說2*2這個位置。
有兩種擺法,我當時就在想如何記錄result[1][1]=2,因為這兩種條件都滿足了,所以result[1][1]=2?那之後的result[1][2]呢?
覺得這樣不對。就完全沒有思路了。
最後看了一個動態規劃演算法,但其實這道題算動態規劃的話,我更覺得像列舉,列舉上樓的所有情況,列舉下樓的所有情況,看這兩種情況裡面,哪些合拍,之後才是動態規劃記錄其和的事。
首先覺得這種記錄方法很棒,即記錄兩層樓的狀態,如果是01代表豎著一個骨牌。如果是10代表,樓上的骨牌怎麼來的不知道,但從樓下豎著一塊牌是確定的。如果是11,說明都是橫著的牌,所以樓上和樓下的下一張牌都要是1才能滿足條件。如果是00,則GG。
之後就是第一層的初始化,只需記住1要成對出現就行了(因為這是第一層)。
被這題折磨太久,印象實在太深。希望交流。
#include <iostream> #include <cstring> using namespace std; #define M 12 long long dp[12][1<<M]; int n,m; int init_ok(int i) { int count; for(count=m-1;count>=0;) { if((i>>count)&1) { if((i>>(count-1))&1) { count= count-2; continue; } else { count--; return 0; } } else { if(count==1&&(i&1)) return 0; else { count--; continue; } } } return 1; } void init() { int count; int kongjian = (1<<m)-1; memset(dp,0,sizeof(dp)); for(count=0;count<=kongjian;count++) { if(init_ok(count)) dp[0][count]=1; } } bool match(int a, int b) { for (int i = 1; i < 1 << m;) { if (((a & i) == 0) && ((b & i) == 0)) return false; if ((a & i) && (b & i)) { if ((a & (i << 1)) && ((b & (i << 1)))) { i <<= 2; continue; } else return false; } i <<= 1; } return true; } int main() { while(scanf_s("%d %d",&n,&m),n &&m) { int i,shang,xia; if(n < m) i = n ,n = m,m =i; int kongjian = (1<<m)-1; init(); for(i=1;i<n;i++) { for(xia = 0;xia<=kongjian;xia++) { for(shang=0;shang<=kongjian;shang++) { if(match(shang,xia)) dp[i][xia]+=dp[i-1][shang]; } } } cout<<dp[n-1][kongjian]<<endl; } return 0; }