状压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 时的可行数目 .

 好多位运算啊啊啊.... 

猜你喜欢

转载自blog.csdn.net/qq_41661809/article/details/81534825