您的位置:首页 > 其它

[BZOJ1725][Usaco2006 Nov]Corn Fields牧场的安排(状压dp)

2016-04-24 22:10 507 查看

题目描述

传送门

题解

预处理出状态每一行是否可行、两两关系是否可行。

状态:f[i][j]表示种到第i行,第i行状态为j的方案数。

转移:f[i][j]=(f[i][j]+f[i-1][k])%Mod;j和k分别表示这一行和上一行的状态。

初始化:f[1][所有状态]=1,其余为0

目标:∑i=0totf[n][i]其中tot为状态总数

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int N=13;
const int Mod=1e8;
int n,m,tot,x,s[N],mi[N],state[N],f[N][1<<(N-1)],ans;
bool line[1<<(N-1)],ok[1<<(N-1)][1<<(N-1)],situ[N][1<<(N-1)];

int main(){
mi[0]=1; for (int i=1;i<N;++i) mi[i]=mi[i-1]<<1;
scanf("%d%d",&n,&m); tot=(1<<m)-1;
for (int i=1;i<=n;++i){
for (int j=m;j>=1;--j) scanf("%d",&s[j]); x=0;
for (int j=1;j<=m;++j) x+=mi[j-1]*s[j]; state[i]=x;
}
for (int i=0;i<=tot;++i)
if (((i>>1)&i)==0)
line[i]=true;
for (int i=0;i<=tot;++i) if (line[i])
for (int j=0;j<=tot;++j) if (line[j])
if ((i&j)==0)
ok[i][j]=true;
for (int i=1;i<=n;++i)
for (int j=0;j<=tot;++j)
if ((state[i]|j)==state[i])
situ[i][j]=true;
for (int i=0;i<=tot;++i) if (situ[1][i]&&line[i]) f[1][i]=1;
for (int i=2;i<=n;++i)
for (int j=0;j<=tot;++j)
if (line[j]&&situ[i][j])
for (int k=0;k<=tot;++k)
if (line[k]&&situ[i-1][k])
if (ok[j][k])
f[i][j]=(f[i][j]+f[i-1][k])%Mod;
for (int i=0;i<=tot;++i) ans=(ans+f
[i])%Mod;
printf("%d\n",ans);
}


总结

内存算好!

本来1A的题手残内存多打了嘿嘿嘿
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: