1. 程式人生 > >【題解】 P1879 玉米田Corn Fields (動態規劃,狀態壓縮)

【題解】 P1879 玉米田Corn Fields (動態規劃,狀態壓縮)

bad sin 是否 editor infer nbsp 一行 als clas

題目描述

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.

農場主John新買了一塊長方形的新牧場,這塊牧場被劃分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一塊正方形的土地。John打算在牧場上的某幾格裏種上美味的草,供他的奶牛們享用。

遺憾的是,有些土地相當貧瘠,不能用來種草。並且,奶牛們喜歡獨占一塊草地的感覺,於是John不會選擇兩塊相鄰的土地,也就是說,沒有哪兩塊草地有公共邊。

John想知道,如果不考慮草地的總塊數,那麽,一共有多少種種植方案可供他選擇?(當然,把新牧場完全荒廢也是一種方案)

輸入輸出格式

輸入格式:

第一行:兩個整數M和N,用空格隔開。

第2到第M+1行:每行包含N個用空格隔開的整數,描述了每塊土地的狀態。第i+1行描述了第i行的土地,所有整數均為0或1,是1的話,表示這塊土地足夠肥沃,0則表示這塊土地不適合種草。

輸出格式:

一個整數,即牧場分配總方案數除以100,000,000的余數。

輸入輸出樣例

輸入樣例#1:
復制
2 3
1 1 1
0 1 0
輸出樣例#1: 復制
9

Solution:
  
一道標準動規題,由n<=12很容易聯想到狀壓,如果定義dp[i][j]表示i,j這個點左上部分的矩陣的方案數,但是不好轉移,並且狀壓沒有體現。
  這時候我們可以想,狀壓壓什麽,可以直接壓一行種草的位置,種草即為1,不種草即為0,這時候可以定義dp[i][k] i表示到第i行,狀態為k時前面的狀態
  轉移方程就很容易想了,dp[i][k]是由上一行狀態轉移過來。
  簡單來說:dp[i][k]=∑(k‘滿足情況) dp[i-1][k‘]
  k‘需要滿足什麽情況呢:
    
1.滿足輸入矩陣規定的1與0,即判斷每個位置種草是否合法
    2.滿足不與上一行沖突,保證上一行狀態為1的位置,這一行不為1,這就把兩個狀態&計算起來,即k&k‘ 若為0,即不沖突(可以好好理解下)

  然後一行一行dp計算就可以了

Code:
  
 1 //It is coded by Ning_Mew on 2.25
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<cstdlib>
 6 #include<cstring>
 7 #include<algorithm>
 8 using namespace std;
 9 const int MOD=100000000;
10 int n,m,ans=0;
11 int a[15][15];
12 int num[15][15];
13 int dp[15][1<<13];
14 
15 void dfs(int x,int y){
16   if(y>m){x++;y=1;}
17   if(x==n+1&&y==1){ans++;ans%=MOD;return;}
18   if(a[x][y]){
19     if(num[x-1][y]||num[x][y-1]){
20       num[x][y]=0;dfs(x,y+1);
21     }
22     else{
23       num[x][y]=0;dfs(x,y+1);
24       num[x][y]=1;dfs(x,y+1);
25     }
26   }
27   else{num[x][y]=0;dfs(x,y+1);}
28   return;
29 }
30 bool check(int k,int l){
31   for(int i=1;i<=m;i++){
32     int ii=1+m-i;
33     //cout<<k<<‘ ‘<<ii<<‘ ‘<<((k>>(i-1))&1)<<endl;
34     if(a[l][ii]==0&&((k>>(ii-1))&1)==1)return false;
35   }
36   for(int i=1;i<=m;i++){
37     int ii=1+m-i;
38     if((k>>(ii-1)&1)==1&&((k>>ii)&1==1))return false;
39   }
40   return true;
41 }
42 int main(){
43   scanf("%d%d",&n,&m);
44   for(int i=1;i<=n;i++){
45     for(int j=1;j<=m;j++){scanf("%d",&a[i][j]);}
46   }
47   if(n<=3&&m<=3){
48     dfs(1,1);
49     printf("%d\n",ans);return 0;
50   }
51   
52   for(int i=0;i<=(1<<m)-1;i++){
53     if(check(i,1)){
54       //cout<<i<<endl;
55       dp[1][i]=1;
56     }
57   }
58   for(int i=2;i<=n;i++){
59     for(int k=0;k<=(1<<m)-1;k++){
60       if(!check(k,i))continue;
61       for(int kk=0;kk<=(1<<m)-1;kk++){
62     if((k&kk)==0){
63       dp[i][k]=dp[i][k]+dp[i-1][kk];
64       dp[i][k]=dp[i][k]%MOD;
65     }
66       }
67     }
68   }
69   for(int i=0;i<=(1<<m)-1;i++)ans=(ans+dp[n][i])%MOD;
70   printf("%d\n",ans);
71   return 0;
72 }

  轉載附上本蒟蒻的鏈接和我說一聲就ok了~ http://www.cnblogs.com/Ning-Mew/p/8469408.html

 

【題解】 P1879 玉米田Corn Fields (動態規劃,狀態壓縮)