合理安排(状压dp,包括技巧判断子集)

第4题     合理安排 查看测评数据信息

花园主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则表示土壤不适合种植。

1<=M<=12,1<=N<=12

 

输出格式

 

一个整数,即牧场分配总方案数除以100000000的余数。

 

输入/输出例子1

输入:

2 3

1 1 1

0 1 0

 

输出:

9

 

样例解释

 

 

注意到范围很小,且和dp可能扯上关系

考虑状压。

但是题目给了一些限制条件

1.对于同一行,相邻列不同时为1,开个循环判断即可,假设本行选了状态是s, (s<<i) & (s<<(i+1)) ==0,s的第 i 位和第 i+1 位不同时为1即可。

2.对于不同行,相同列,相邻行不同时为1,这个更简单了,假设第一行选了状态是x,第二行选了状态是y,x & y == 0

 

然后我们可以预处理每一行的合法状态,装入vec,这样可以减少枚举量,也方便一些

状态和转移就显而易见了。

f(i, s) 当前考虑前i行,并且第i行的状态是s的方案数

假设s2是第i行选的状态,s1是第i-1行选的状态。满足限制条件时(只有限制2,因为这是对于不同行时的转移),f(i, s2) += f(i-1, s1)

 

 

如何预处理合法状态?这里给一个小知识点

判断一个集合是否是另外一个集合的子集

s2 & s == s2
s2是s的子集

 

所以我们先处理每一行合法状态的最大值(就是每一行,可以种植的地,对应的二进制和)

如何枚举二进制状态,前提是每个二进制状态是合法状态最大值的子集才行,如何因为这是同一行,就只有限制1了。

 

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=15, M=8500, Mod=100000000;

int n, m, a[N][N], f[N][M], ans=0;
vector<int> v[N];
bool check(int x)
{
	for (int i=0; i<=12; i++)
		if (((x<<i) & (x<<(i+1)))!=0) return 0;
	
	return 1;
}
signed main()
{
	scanf("%lld%lld", &n, &m);
	for (int i=1; i<=n; i++)
		for (int j=1; j<=m; j++)
			scanf("%lld", &a[i][j]);
			
	for (int i=1; i<=n; i++) 
	{
		int s=0;
		for (int j=1; j<=m; j++)
			if (a[i][j]) s+=(1<<(j-1));
		
		for (int j=0; j<(1<<m); j++)
			if ((j&s)==j && check(j)) v[i].push_back(j);
	}
	
	for (int i=0; i<v[1].size(); i++) f[1][v[1][i]]=1;
	
	for (int i=2; i<=n; i++)
		for (int j=0; j<v[i].size(); j++)
			for (int k=0; k<v[i-1].size(); k++)
				if ((v[i][j]&v[i-1][k])==0) f[i][v[i][j]]=(f[i][v[i][j]]+f[i-1][v[i-1][k]])%Mod;
	
	for (int i=0; i<v[n].size(); i++) ans=(ans+f[n][v[n][i]])%Mod;	
	
	printf("%lld", ans);
	return 0;
}

  

 

posted @ 2024-08-20 07:42  cn是大帅哥886  阅读(22)  评论(0)    收藏  举报