POJ - 3254 (2020.4.23训练B题)

Problem
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.

题意:有个M×N的方格图,牛食草,方格值为1即可食草,0不可,放牧的位置不可连续,求一共多少种方案(不食草也是一种方案)

典型的状压dp题,每行的情况降维压缩,开一个二维dp数组存储方案数,最后累加取模,具体详见代码注释

AC代码

#include<iostream>
#include<string>
using namespace std;
int M, N;
const int mod = 100000000;
int vis[30];//cur[i]表示第i行整行的情况,用二进制数表示
int state[700];//state数组存每行满足不连续食草的所有可能状态
int dp[30][700];//dp数组表示第i行的第j种状态有多少种方案
int num, top = 0;
inline bool judge(int x)//判断状态x是否可行
{
	if (x & x << 1)return false;
	else return true;
}
void init()
{
	int total = 1 << N;//total表示一行状态的总数
	top = 0;//top表示一行满足不连续食草的可能状态总数
	for (int i = 0; i < total; i++)
	{

		if (judge(i))
		{

			state[++top] = i;
		}
	}
}
inline bool fit(int x, int k)//用来判断某行的一种状态是否与原情况相符合,比如0的地方不能突然出了个1,是不符合的
{
	if (x & vis[k])return false;
	else return true;
}
int main()
{
	cin >> M >> N;
	init();
	for (int i = 1; i <= M; i++)
	{

		for (int j = 1; j <= N; j++)
		{

			cin >> num;
			if (num == 0)//只能存逆状态,方便初始化第一行状态
			{

				vis[i] += (1 << (N - j));
			}
		}
	}
	for (int i = 1; i <= top; i++)
	{
		
		if (fit(state[i], 1))//记住要初始化第一行
			dp[1][i] = 1;
	}
	for (int i = 2; i <= M; i++)//从第二行开始递推统计方案数
	{
	
		for (int k = 1; k <= top; k++)//出现不符合情况的一律continue,出现符合为止
		{
		
			if (!fit(state[k], i)) continue;
			for (int j = 1; j <= top; j++)
			{
			
				if (!fit(state[j], i - 1)) continue;
				if (state[k] & state[j])continue;
				dp[i][k] = (dp[i][k] + dp[i - 1][j]) % mod;//状态转移方程
			}
		}
	}
	int ans = 0;
	for (int i = 1; i <= top; i++)
	{
	
		ans = (ans + dp[M][i]) % mod;//最后一行每种状态对应方案数累加
	}
	cout << ans << endl;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值