您的位置:首页 > 其它

PKU 3254 状态压缩DP

2011-08-11 23:37 232 查看
http://poj.org/problem?id=3254

题意:输入一个n*m的矩阵,矩阵由数字0和1组成,0表示不能种植玉米的草地,1表示能够种植玉米的草地。然后在种植了玉米的草地上放牛,放牛的数目随意,但是要满足相邻的草地间不能同时放牛,要求所有放牛的方案总数。

例如:

2 3
1 1 1
0 1 0

方案总数为9,因为将每块草地编号后得到
1 2 3
0 4 0

一头都不放有1种情况,放一头牛的方案为1,2,3,4都行,有4种,放两头牛的方案有(1,3) (1 4) (3 4),有3中,放三头牛的方案有(1,3,4)一种,一共9种!

分析:地图显然是0和1构成,即用0,1来表示所有的情况,所以显然是二进制的情况,即用二进制来表示所有情况的一种题型。

我们可以使用二进制的状态压缩,用一个数来表示某一行的放牛情况,例如某一行的放牛方案为5,而五的二进制表示为1 0 1,对于上面的数据来说,相邻的没有放牛,并且放牛的地方都有种植玉米,所以这是一种可行的方案。那么第一行到底有多少可行的方案呢,由于相邻的玉米间不许放牛,不难看出有

(0,0,0)[0] 、 (1,0,0)[4] 、 (0,1,0)[2] 、 (0,0,1)[1] 、 (1,0,1)[5]

再看第二行,它的所有方案为

(0,0,0)[0] 、 (0,1,0)[2]

现在状态压缩已经完毕,我们要开始动规,动规是从第一行一直到最后一行。

我们开设数组dp[i][j],表示第i行取第j种状态的所有可行方案总数。

看上面的数据,第一行取0,4,2,1,5五种状态中的一种都只有一种情况,所有dp[1][i]=1.(i=1,2,3,4,5)。

再看第二行的第一种状态0,如果第二行取了0的话,也就是说第二行不放牛,那么第二行和第一行的任何一种状态都不矛盾(上下相邻的不能放牛),那么第一行的所有情况都可以取到,于是dp[2][1]=5。

再看第二个状态2.,如果取了2的话,那么第二行将和第一行的状态2发生矛盾,即放牛情况为

0 1 0

0 1 0

很显然的看到上下相邻了,所以第二行的状态2只能和第一行的状态0,4,1,5共存,即dp[2][2]=4。

最后我们将最后一行的所有状态的dp值相加,便得到了我们要求的答案~~dp[2][1]+dp[2][2]=5+4=9

View Code

#include<iostream>
#include<string>
using namespace std;
#define maxn (1<<12)

int map[14][14];
int dp[14][maxn+2];
int n,m,i,j;

void dfs(int k,int state) //所有状态顺序都是从右往左,即k的增加说明了状态在向左进位
{
if(k==m)
{
dp[i+1][state]+=dp[i][j];
return;
}
if(!map[i+1][m-k-1]) //没有玉米
{
dfs(k+1,state);  //状态保持不变
}
else
{
if(((j>>k)&1)==0)
{
if(k==0)
dfs(k+1,state|1<<k);  //该位置k放了牛,则state在k位上加1
if(k-1>=0 && ((state>>(k-1))&1)==0) //并且它右边相邻的地里没有放牛
dfs(k+1,state|1<<k);  //同上
}
dfs(k+1,state);
}
}

int main()
{
freopen("D:\\in.txt","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n;i++)
{
for(j=0;j<m;j++)
{
scanf("%d",&map[i][j]);
}
}
memset(dp,0,sizeof(dp));
dp[0][0]=1;   //地图是从1到n,这里人工的将地图扩大一行,第零行一个玉米都不种,这样便有了初始值,又不影响接下来的搜索
for(i=0;i<n;i++) //注意i,j是全局变量,j便是第i行的状态
{
for(j=0;j<(1<<m);j++)
{
if(dp[i][j])
{
dfs(0,0);  //对i+1行进行DP,可达的所有状态dp[i+1][j]都将加上dp[i][j]
}
}
}
int ans=0;
for(i=0;i<(1<<m);i++)
{
ans=(ans+dp
[i])%100000000;
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: