狀壓dp POJ 3254 農夫玉公尺田

2021-09-24 19:34:41 字數 1735 閱讀 4072

轉大佬的思路:

對於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

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 時...