洛谷1879-[USACO06NOV]Corn Fields G-玉米田(状压dp)

传送门

题目描述

在这里插入图片描述

输入描述

在这里插入图片描述

输出描述

在这里插入图片描述

输入样例

2 3
1 1 1
0 1 0

输出样例

9

互不侵犯 的青春版(?),本题省去了对于数量上限的要求,因此仅需使用二维状态 f [ i ] [ j ] 即可,其中 i 表示种到了第 i 行,j 表示该行是以第 j 种状态种地。

对于每一行,同样进行初始化枚举每一种状态是否符合种地要求,若存在相邻的 1 则将该状态标为非法。

状态转移方程:

f [ i ] [ j ] = f [ i − 1 ] [ x ] f[i][j]=f[i-1][x] f[i][j]=f[i1][x]

其中 x 表示上一行采用的种地状态。

本题中唯一的特殊点是:某些地可能不允许种。因此对于即将转移到的第 i 行,需要考虑状态 j 是否与这一行的土地状态相匹配,若改行的某个土地为不允许播种,而状态 j 在该土地上种植了作物,则该状态与该行冲突,直接忽略即可。

由于数据范围不是很大,直接在答案处取模即可。

参考代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=15,M=1<<14;
int g[N][N];//存放土地情况 
bool st[M];
ll f[N][M];
int mod=1e8;

int n,m;

bool check(int col,int now){
    
    
	if(!st[now])
		return false;
	for(int j=1;j<=m;j++){
    
    
		if((g[col][j]==0)&&(((now>>(m-j))&1)==1))
			return false;
	}
	return true;
}

int main(){
    
    
	cin>>n>>m;
	for(int i=1;i<=n;i++){
    
    
		for(int j=1;j<=m;j++){
    
    
			cin>>g[i][j];
		}
	}
	
	//预处理
	for(int i=0;i<1<<m;i++){
    
    
		st[i]=true;
		for(int j=0;j<m;j++){
    
    
			if(((i>>j)&1)&&(i>>(j+1)&1))
				st[i]=false;
		}
	} 
	
	f[0][0]=1;
	
	for(int i=1;i<=n+1;i++){
    
    
		for(int j=0;j<1<<m;j++){
    
    
			for(int x=0;x<1<<m;x++){
    
    
				if(!check(i,j))
					continue;
				if((j&x)!=0)
					continue;
				f[i][j]=(f[i-1][x]+f[i][j]);
			}
		}
	}
	
	cout<<f[n+1][0]%mod;
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/laysan/article/details/121308648
今日推荐