POJ 3254. Corn Fields 狀態壓縮DP (入門級)


Corn Fields
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 9806   Accepted: 5185

Description

Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and can't be planted. Canny FJ knows that the cows dislike eating close to each other, so when choosing which squares to plant, he avoids choosing squares that are adjacent; no two chosen squares share an edge. He has not yet made the final choice as to which squares to plant.

Being a very open-minded man, Farmer John wants to consider all possible options for how to choose the squares for planting. He is so open-minded that he considers choosing no squares as a valid option! Please help Farmer John determine the number of ways he can choose the squares to plant.

Input

Line 1: Two space-separated integers:  M and  N 
Lines 2.. M+1: Line  i+1 describes row  i of the pasture with  N space-separated integers indicating whether a square is fertile (1 for fertile, 0 for infertile)

Output

Line 1: One integer: the number of ways that FJ can choose the squares modulo 100,000,000.

Sample Input

2 3
1 1 1
0 1 0

Sample Output

9

Hint

Number the squares as follows:
1 2 3
  4  

There are four ways to plant only on one squares (1, 2, 3, or 4), three ways to plant on two squares (13, 14, or 34), 1 way to plant on three squares (134), and one way to plant on no squares. 4+3+1+1=9.

Source

 

 
 
          題目大意是有M×N的玉米地,但其中有些是不肥沃的,不能種植。用1來代表肥沃,0代表不肥沃。另外奶牛不喜歡挨着吃,也就是說要間隔着種植,求有幾種種植方式,並將計算結果對1E8取模。
          對於0-1狀態矩陣,自然而然會想到用狀態壓縮來做,把一行(也可以按列)的狀態壓縮成一個十進制數(行狀態)。另種植or不種植也可以用0-1表示,並根據題目所說不能挨着種植,即這一行的某個位置種植了,下一行的同一位置就不能種植,可以知道兩行的種植狀態相位與要為0
          另外說一個行種植狀態有效,即相鄰的格子是不能種植的,需要 左移一位后與自身相位與為0 ,如果存在相鄰種植的格子,則一定會保留位1,不可能得出0的結果,據此枚舉出這些狀態再進行判斷。
          然而並不是每個有效的行種植狀態對於每一行都有效,因為有的行存在一些位置是不能種植的,用0表示。為了方便判斷和計算,我們考慮將行狀態取反,即0表示肥沃,1表示不肥沃,這樣只有當行種植狀態和行狀態相位與為0,這個種植狀態才在該行有效,因為如果種在了不肥沃的格子上,相位與會保留位1,結果不為0。
          於是我們 有以下設計思路:
                    ①在讀入時就將格子狀態取反,壓縮成行狀態存到row[]數組里;
                    ②枚舉所有有效的種植狀態,存到rec[]數組里,並將最大值存進去避免后面越界;
                    ③先處理第一行,給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 #include <stdio.h>
 2 #define MOD 100000000
 3 int row[13], rec[377], dp[13][377];
 4 int main()
 5 {
 6     int x=1<<12, k=0;
 7     for(int i=0; i<x; i++)                      //calculate all valid states
 8         if(!(i&(i<<1)))                         //is a valid row state
 9             rec[k++]=i;
10     rec[k]=x;
11 
12     int M, N, t;
13     scanf("%d%d", &M, &N);
14     for(int i=0; i<M; i++)
15         for(int j=0; j<N; j++)
16             scanf("%d", &t),                    //t = Matrix[i][j]
17             row[i]=(row[i]<<1)|!t;              //reverse row state
18 
19     x=1<<N;
20     for(int i=0; rec[i]<x; i++)                 //process first row
21         if(!(row[0]&rec[i]))
22             dp[0][i]=1;
23     for(int r=1; r<M; r++)                      //for each row
24         for(int i=0; rec[i]<x; i++)             //for each valid state for last row
25             if(!(row[r-1]&rec[i]))
26                 for(int j=0; rec[j]<x; j++)     //for each valid state for this row
27                     if(!(row[r]&rec[j]))
28                         if(!(rec[i]&rec[j]))    //the two states are not conflict
29                             dp[r][j]=(dp[r][j]+dp[r-1][i])%MOD;
30 
31     int r=M-1;
32     for(int i=1; rec[i]<x; i++)                 //process last row
33         dp[r][0]=(dp[r][0]+dp[r][i])%MOD;
34     printf("%d\n", dp[r][0]);
35 
36     return 0;
37 }
 
          當然有進一步的空間優化:可以考慮不開二維數組,而是用兩個一維數組來交換值,或者用兩個動態數組,交換指針。即所謂的滾動數組。如果讀者看懂了或自己實現了代碼,就不難理解,不再詳述。 by BlackStorm
 
 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM