轉大佬的思路:
對於0-1狀態矩陣,自然而然會想到用狀態壓縮來做,把一行(也可以按列)的狀態壓縮成乙個十進位制數(行狀態)。另種植or不種植也可以用0-1表示,並根據題目所說不能挨著種植,即這一行的某個位置種植了,下一行的同一位置就不能種植,可以知道兩行的種植狀態相位與要為0。
另外說乙個行種植狀態有效,即相鄰的格仔是不能種植的,需要左移一位後與自身相位與為0,如果存在相鄰種植的格仔,則一定會保留位1,不可能得出0的結果,據此列舉出這些狀態再進行判斷。
然而並不是每個有效的行種植狀態對於每一行都有效,因為有的行存在一些位置是不能種植的,用0表示。為了方便判斷和計算,我們考慮將行狀態取反,即0表示肥沃,1表示不肥沃,這樣只有當行種植狀態和行狀態相位與為0,這個種植狀態才在該行有效,因為如果種在了不肥沃的格仔上,相位與會保留位1,結果不為0。
於是我們有以下設計思路:
①列舉所有有效的種植狀態,存到rec陣列裡,並將最大值存進去避免後面越界;
②在讀入時就將格仔狀態取反,壓縮成行狀態存到row陣列裡;
③先處理第一行,給dp乙個基準:對於每個有效種植狀態,如果在第一行也有效,計數1次;
④對於剩餘的行,不僅要判斷每個有效種植狀態,還要判斷兩行的種植狀態有沒有衝突;
⑤對於最後一行,把每個種植狀態的計數加起來,就是總的種植方法數。
以及dp陣列:dp[r][j]表示當第r行的種植狀態為第j種狀態時,現在玉公尺地的種植方案數。
狀態轉移方程: dp[r][j] = dp[r-1][i] + dp[r][j], if row[i-1]&rec[i]=0 and row[i]&rec[j]=0 and rec[i]&rec[j]=0.
即rec[i]是row[i-1]的有效行狀態,且rec[j]是row[r]的有效行狀態,且rec[i]和rec[j]兩個行狀態不發生衝突。
很重要的結論:
1:預處理滿足沒有相鄰放牧的所有的行時:需要左移一位後與自身相位與為0
2:所有滿足的可能行於現在這個行沒有衝突的條件:當行種植狀態和行狀態相位與為0
3:於上一行的狀態沒有衝突:兩行的種植狀態相位與要為0。
位運算很重要!位運算很重要!位運算很重要!還有不要把&寫成&&。
#include
using
namespace std;
const
int mod=
100000000
;int xx[
377]
;//所有合法的行狀態
int now[13]
;//目前輸入的行狀態
int dp[13]
[377];
intmain()
} xx[k]
=x;//結束標誌
int n, m, t;
scanf
("%d%d"
,&n,
&m);
for(
int i=
0;ix=
1/x目前的最大值
for(
int i=
0;xx[i]
)//預處理第一行狀態
}for
(int h=
1;h}}}}
int ans=0;
for(
int i=
0;xx[i]
)//最後一行的狀態和為答案
printf
("%d\n"
, ans)
;return0;
}
狀壓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 看著妥妥超時,但是裡面合法狀態很少 依舊可以過 在此,...
狀壓DP 玉公尺田
農夫約翰的土地由m n個小方格組成,現在他要在土地裡種植玉公尺。非常遺憾,部分土地是不育的,無法種植。而且,相鄰的土地不能同時種植玉公尺,也就是說種植玉公尺的所有方格之間都不會有公共邊緣。現在給定土地的大小,請你求出共有多少種種植方法。土地上什麼都不種也算一種方法。輸入格式 第1行包含兩個整數m和n...
題解 poj3254 狀壓DP
題目鏈結 思路摘抄自大佬部落格 狀態可由二進位制表示,只需將每種狀態轉化為相應的十進位制數,即可只用乙個數字,就能表示某一種狀態 以dp i state j 來表示對於前i行,第i行採用第j種狀態時可以得到的可行方案總數!例如 回頭看樣例資料,dp 2 1 即代表第二行使用第2中狀態 0 1 0 時...