poj3254 Corn Fields(状压dp基础题)

题意

一些地方可以种地(用1表示),一些地方不能(用0表示)

相邻的1不能同时种地,问有多少种可行种地方案

思路来源

https://www.bilibili.com/video/av29915579/?spm_id_from=333.788.videocard.0

题解

判 左右不相邻(now&(now<<1))==0

判 上下不相邻  (pre&now)==0

判  枚举值是当前行的子集 (now|all)==all

心得

dp[0][i]的值怎么赋值呢

看dp[1][j]怎么用到了dp[0][i]的值,按需赋值

比如说dp[1][j]应当赋1的地方,为了统一操作转移到dp[0][i]处,就赋dp[0][i]=1

代码

#include <iostream>
#include <algorithm> 
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <functional>
const int INF=0x3f3f3f3f;
const int maxn=1e2+10; 
const int mod=1e8;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int> 
#define si set<int>
#define pii pair<int,int> 
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a)) 
using namespace std;
int n,m; 
int line[15];
ll dp[15][1<<15];
bool updown(int up,int down)
{
	return (up&down)==0;
}
bool adjacant(int now)
{
	return ((now)&(now<<1))==0;
}
bool subset(int a,int b)//a是b的子集 
{
	return (a|b)==b;
}
void init()
{
	mem(line,0);
	mem(dp,0);
}
int main()
{ 
   while(~scanf("%d%d",&n,&m))
   {
   	init();
   	rep(i,1,n)
   	{
   		int num;
   		rep(j,0,m-1)
   		{
   			sci(num);
   			line[i]=(line[i]<<1)+num;
   		}
   	}
   	dp[0][0]=1;
   	rep(i,1,n)
   	{
   		rep(j,0,line[i])
   		{
   			rep(k,0,line[i-1])//利用line[0]全0,统一操作
			{
				if(updown(j,k)&&adjacant(j)&&subset(j,line[i]))
				{
					dp[i][j]+=dp[i-1][k]%mod;//k不adjacant的话,肯定没被更新,还是0,不用管 
					if(dp[i][j]>=mod)dp[i][j]%=mod;
				}
			} 
   		}
   	}
   	ll ans=0;
   	rep(i,0,line[n]) 
   	{
   		ans+=dp[n][i]; 
   		if(ans>=mod)ans%=mod;
   	}
   	printf("%lld\n",ans);
   }
   return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值