您的位置:首页 > 其它

[poj 3254]Corn Fields[状压DP]

2013-08-16 20:11 295 查看
题意:

一块玉米地,有的位置不能种草,种草的小方格不能有临边. 问有多少种方案.

思路:

状压DP.

dp[ i ][ j ] 表示从上到下处理到第 i 行时, 该行状态为 j 的方案数.

下一行某状态的方案数就是上一行所有合理状态的方案数之和.

注意初始化和最后一行的处理.

#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 14;
const int MOD = 1e8;
typedef long long ll;
int pat[MAXN],m,n;
ll dp[MAXN][1<<MAXN];
inline bool valid(int s,int i)
{
return (s & (~pat[i]))?false:true;
}
inline bool adj(int s)
{
for(int i=0;i<n-1;i++)
{
if((1<<i)&s && (1<<(i+1))&s)    return true;
}
return false;
}
void DP(int i, int s)
{
for(int j=0;j<(1<<n);j++)
{
if(!valid(j,i-1) || (s&j) || adj(j))  continue;
dp[i][s] += dp[i-1][j];
}
dp[i][s] %= MOD;
}

int main()
{
scanf("%d %d",&m,&n);
dp[0][0] = 1;
for(int i=1;i<=m;i++)
{
int t;
for(int j=n-1;j>=0;j--)
{
scanf("%d",&t);
if(t)   pat[i] += 1<<j;
}
for(int j=0;j<(1<<n);j++)
{
if(!valid(j,i)||adj(j))   continue;
DP(i,j);
}
}
DP(m+1,0);
printf("%d",(int)dp[m+1][0]);
}


131007重写:

行标号1-m, 列标号1-n.

dp[i][state]表示处理了1-i行时, 且第i行为state排布时, 一共的方案数.

可以枚举前面的更新后面的, 也可以枚举后面的然后找前面可行的加起来...第一种其实是不需要的, 因为前面不可行的方案数自然是0, 不判断的话也没有影响.

后面的需要满足:

1. 横向不相邻(不同时为1) 2. pat中0的位置不可取(&==0) 3. 与上一行不相邻(~&==0)

先找出后面的可行状态, 再Σ前面不矛盾的状态的方案数. 因为后面的状态需要额外判断本身, 因此枚举后面的.

864K 16MS ..效率低了..

上面的是

440K 0MS...

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 15;
const int MOD = 100000000;
int n,m,pat0,pat[MAXN];
ll dp[MAXN][1<<12];
int main()
{
while(scanf("%d %d",&m,&n)==2)
{
memset(pat,0,sizeof(pat));
for(int i=1;i<=m;i++)
for(int j=0;j<n;j++)
{
scanf("%d",&pat0);
if(!pat0)   pat[i] |= 1<<j;//1==forbiden
}
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for(int i=1;i<=m;i++)//枚举行
for(int state=0;state<1<<n;state++)//枚举当前状态
if((state&pat[i])==0)//符合题设
{
int k;
for(k=1;k<n;k++)//横向不相邻
if(((state>>k)&1) & ((state>>(k-1))&1))  break;
if(k!=n)    continue;
for(int s=0;s<1<<n;s++)//枚举上一行可行的
if(dp[i-1][s] && (state&s)==0)
dp[i][state] += dp[i-1][s];

}
for(int s=0;s<1<<n;s++)
dp[m+1][0] += dp[m][s];
printf("%d\n",(int)(dp[m+1][0]%MOD));
}
}

调用函数判断大概比较快><
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: