1. 程式人生 > >狀壓dp入門第一題

狀壓dp入門第一題

看到dp就頭疼,學完狀壓還是不太明白,唉,腦子笨!...

先來一道模板題水水.

Corn Fields

Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 19718 Accepted: 10338

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.

就是說輸入玉米地的大小,n*m ,然後有的地方不能種,要求同行不相鄰,同列不相鄰.輸出有多少種種法 .

#include <iostream>
#include <cstdio>

using namespace std;
const int MOD = 100000000;
bool e[15][15], in[1 << 14];
int dp[15][1 << 14], n, m;

bool solve(int S, int l)
{
	for (int i = 1; i <= m; i++)
	{
		if (!e[l][i] && (S&(1 << (m - i))))
            // 如果本來不能種,但你中了就return false ;
			return false;
	}
	return true;
}

int main()
{
   // freopen("in.txt","r",stdin);
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++)
    cin >> e[i][j];
	//預處理可行狀態(同行)
	for (int S = 0; S < (1 << m); S++)
	{
		if ((S&(S << 1))==0 )// 如果不相鄰 ,那麼該狀態就ok ;
			in[S] = true;
	}


	for (int S = 0; S < (1 << m); S++)
	{
		if (in[S] && solve(S, 1))
            // 如果滿足不相鄰 ,
			dp[1][S] = 1;
	}
	for (int i = 2; i <= n; i++)
	{
	    // 從第二行開始處理 ;
		for (int j = 0; j < (1 << m); j++)
		{

			for (int S = 0; S < (1 << m); S++)
			{
			    // 列舉狀態 ;
				if (dp[i - 1][S]== 0) // 說明此狀態不行 ;
					continue;
				if (in[j] && solve(j, i) && !(j&S))// (j&S) 篩選同列的狀態 ; 
				{
					dp[i][j] = (dp[i][j] + dp[i - 1][S]) % MOD;
				}
			}
		}
	}
	int ans = 0;
	for (int S = 0; S < (1 << m); S++)
		ans = (ans + dp[n][S]) % MOD;
	cout << ans << endl;
	return 0;
}

滿足條件:

               1  種植的玉米的那塊地是否能改種植玉米 .

               2   同行中不能出現相鄰的 比如 011 , 110 ,111 ,顯然不滿足 ,

              3   同列的不能出現相鄰的比如

                                                                1  :        1 0 1

                                                                2  :        1 0 0 

                 顯然第一行的 1 和 第二行的 1 相鄰了 ,不可以 . 

解釋一下,solve 這個函式來看看你是種植的玉米是否符合那一塊地能不能種玉米,S 代表狀態 , 從 000 ~ 111 ,8種狀態 ,in[]陣列,

用來儲存該行是否滿足 條件 2 .   還有處理同列不相鄰的我們用  (S&S) == 0 , S 表示狀態 ,比如 101 和 100 & 一下 等於100 即 4

不等於0 ,說明不滿足條件 3 .    其中dp[i][S] 表示 第 i 行 狀態為S 時的可行數目 .

 好多位運算啊啊啊....