[poj3254]Corn Fields_狀壓dp
阿新 • • 發佈:2018-03-14
nbsp 可能 運用 局限 scanf field efi string 調試
Corn Fields poj3254
題目大意:給你一個n*m的地,每一塊地可以種或不種,兩塊種過的地不能挨著,可以一塊都不種,問所有的種地方案數。
註釋:讀入用0和1,1<=n,m<=12.
想法:這題和炮兵陣地特別像,比炮兵更簡單。我們再度入的時候直接處理出當前行的地的不可種的情況。預處理出一行如果都能種的話所可能的方案數。此處需要滿足的就是兩塊地不能挨著,通過打表我們可以發現這種情況最多只有377種情況(我們附上打表用的程序)
#include <iostream> #include <cstdio> #include <cstring> using namespace std; bool check(int x)//判斷當前狀態是否可行 { if(x&(x<<1)) return false; return true; } int cnt; void before(int mid)//處理所有狀態 { for(int i=0;i<(1<<mid);i++) { if(check(i)) cnt++; } } int main() { int n; cin >> n; before(n); printf("%d\n",cnt);//輸出所有可行狀態數 return 0; }
然後,我們先預處理出第一行,怎麽處理呢?其實map是0的情況,也就是讀入數據的反碼。我們對於一個狀態只需要通過&上map對應的下標就可以判斷當前數據是否合法。如果合法,dp[1][i]就是1。其中,dp[i][j]表示第 i 行狀態為 j ,前 i 行能填充的方案數。轉移時,我們通過外層松弛行數,內層枚舉所有狀態,用&判斷即可。
最後,附上醜陋的代碼... ...
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define mod 1000000000 using namespace std; int dp[15][380]; int map[15];//存儲的是反碼 int str[380];//存儲所有狀態 // int sum[350]; int cnt;//狀態數目 bool check(int x)//判斷當前狀態是否可行 { if(x&(x<<1)) return false; return true; } // int getSum(int x) // { // int ans=0; // while(x>0) // { // if(x&1) ans++; // x>>=1; // } // return ans; // } void before(int mid)//預處理所有狀態 { for(int i=0;i<(1<<mid);i++) { if(check(i)) { str[++cnt]=i; // sum[cnt]=getSum(i); } } } int main() { int n,m; cin >> n >> m; int a; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%d", &a); if(a==0) map[i]|=(1<<(j-1));//運用|運算的性質來構造反碼 } } before(m);//預處理 // cout << "cnt = " << cnt << endl; for(int i=1;i<=cnt;i++) { if(!(str[i] & map[1])) { dp[1][i]=1; } } // for(int i=1;i<=n;i++) printf("%d ",map[i]); // puts(""); // for(int i=1;i<=cnt;i++) printf("%d ",dp[1][i]); // puts(""); for(int i=2;i<=n;i++)//轉移 { for(int j=1;j<=cnt;j++)//枚舉i的狀態 { if(str[j] & map[i]) continue;//判斷狀態是否合法 for(int k=1;k<=cnt;k++)//枚舉i-1的狀態 { if(str[k] & map[i-1]) continue; if(str[j] & str[k]) continue; dp[i][j]+=dp[i-1][k]; } } } int ans=0; for(int i=1;i<=cnt;i++) { if(map[n]&str[i]) continue; ans+=dp[n][i]; ans%=mod;//重要,不加luogu會WA 10% } printf("%d\n",ans); return 0; }
小結:第2道狀壓。調試時候不要忘記題目所求的,在發現一個題與另一個題相似時不要被另一道題所局限
[poj3254]Corn Fields_狀壓dp