【POJ3254】Corn Fields


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

USACO 2006 November Gold

 

 

好的,來個翻譯啊

 

農場主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的余數。

 

 

 

算法:

狀壓DP

 

分析:

這道題一看就條件反射是動態規划。

但是呢,假如用普通的dp寫這道題可能會掛,畢竟狀態這么多,每個格子取一種狀態的話,我還不如用dfs。

DP的要素有狀態、階段、決策、狀態轉移方程、邊界情況、初始化,前幾天學的樹形DP呢,是從初始化(變成樹狀)和狀態轉移(記憶化搜索)的方面入手進行優化的。而今天既然狀態特多而且千篇一律(都是0或1),那么我們可以通過狀態壓縮來優化動態規划。

 

假如我將二進制位來保存每個狀態的話,那么一行的狀態就可以表示成一個十進制數,而這個十進制數就可以寫成一個二進制的01串,每個位置就是相應的狀態。

 

這些都全靠狀態的單一性和數量巨大,但是位數不能巨大,否則會爆。

 

狀態要初始的時候預存下來,后面再對比狀態的可行性。

 

這里巧用位運算是快速解決狀壓dp的關鍵。

 

上代碼:

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cctype>
 4 #define mod 100000000    
 5 #define C continue                                        //懶得打hhhhh
 6 using namespace std;
 7 
 8 int n,m,tot,state[1500],dp[15][1500],ans,cur[15];        //dp表示當前最大值,第一維是行數,第二維是狀態數,cur是每行的情況,state是預存的可能狀態
 9 
10 inline int read()                                //讀入優化
11 {
12     int x=0,f=1;
13     char c=getchar();
14     while (!isdigit(c))
15         f=c=='-'?-1:1,c=getchar();
16     while (isdigit(c))
17         x=(x<<1)+(x<<3)+(c^48),c=getchar();
18     return x*f;
19 }
20 
21 inline bool fit(int x,int k)                            //判斷當前狀態是否符合當前行
22 {
23     return !(state[x]&cur[k]);
24 }
25 
26 inline void init()                                //初始化
27 {
28     int sum=1<<n,i;            //列舉可能狀態,並預存
29     for (i=0;i<sum;i++)
30         if (!(i&(i<<1)))
31             state[++tot]=i;
32 }
33 
34 int main()
35 {
36     int i,j,k;
37     m=read();
38     n=read();
39     init();
40     for (i=1;i<=m;i++)
41         for (j=1;j<=n;j++)
42         {
43             k=read();
44             if (!k)
45                 cur[i]+=(1<<(n-j));                    //此處注意,cur是不合法才是1
46         }
47     for (i=1;i<=tot;i++)                                //初始化第一行
48         if (fit(i,1))
49             dp[1][i]=1;
50     for (i=2;i<=m;i++)                                //枚舉行
51         for (j=1;j<=tot;j++)                            //枚舉當前狀態
52         {
53             if (!fit(j,i))
54                 C;
55             for (k=1;k<=tot;k++)                //枚舉上一層可行狀態
56             {
57                 if (!fit(k,i-1))
58                     C;
59                 if (state[j]&state[k])
60                     C;
61                 dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;        //狀態轉移
62             }
63         }
64     for (i=1;i<=tot;i++)
65         ans=(ans+dp[m][i])%mod;
66     printf("%d",ans);
67     return 0;
68 }

 

其實只要普通的狀態轉移方程列出來了,優化就好做了。

 

嗯,就這樣了。


免責聲明!

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



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