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

题目描述

传送门

题解

预处理出状态每一行是否可行、两两关系是否可行。
状态: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[n][i])%Mod;
 printf("%d\n",ans);
}

总结

内存算好!
本来1A的题手残内存多打了嘿嘿嘿

你可能感兴趣的:(dp,bzoj)