POJ 3254 Corn Fields 状压DP
题意:给出N*M的01矩阵(N<12&&M<12),0不可以种草,1可以种草,要求种的草不能相邻(不可以共享一个边),问有多少种种法
第一道状压DP,应该来说不算难,看了这个博客,受益很大 http://www.cnblogs.com/ka200812/archive/2011/08/11/2135607.html
注:DFS的话,2的次方级,会爆的。 由题目的特点,下一行只受上一行的影响,而且还有重复计算(下一行的某一状态的数量由上一行得来),说的那么乱呢,
看连接的博客吧,讲的真不错
1.判断一个二进制数有没有相邻的两位同为1的方法 i&(1<<1)||i&(i>>1) 位运算的优先级比较低,一般加()
2.判断两个二进制的数有没有相同位上都为1 直接相与 。 为了方便,代码中还把输入翻了过来,1变成0,0变成1,为了Get_state()里面找状态方便...
代码(带预处理的 0MS):
/*
vector
vetor<int>num[];
num[i].clear();
num[i].push_back();
num[i].size();
num[i][j]
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#define MOD 100000000
#define ll __int64
using namespace std;
int state[13][8192];
ll dp[13][8192];
vector<int>num[13];
int r,c;
void Get_state(int row,int temp)
{
num[row].clear();
for(int i=0;i<(1<<c);i++)
{
if(i&(i>>1)||i&(i<<1)) continue;
if(i&temp) continue;
num[row].push_back(i);
}
}
int main()
{
int i,j,k;
int temp;
while(~scanf("%d%d",&r,&c))
{
for(i=0;i<r;i++)
{
temp=0;
for(j=0;j<c;j++)
{
scanf("%d",&k);
k=1-k;
temp=(temp<<1)+k;
}
Get_state(i,temp);
}
memset(dp,0,sizeof(dp));
for(i=0;i<num[0].size();i++) dp[0][i]=1;
for(i=1;i<r;i++)
{
for(j=0;j<num[i].size();j++)
{
for(k=0;k<num[i-1].size();k++)
{
if(num[i][j]&num[i-1][k]) continue;
dp[i][j]+=dp[i-1][k];
}
}
}
int ans=0;
for(i=0;i<num[r-1].size();i++)
{
ans=(ans+(dp[r-1][i]%MOD))%MOD;
}
printf("%d\n",ans);
}
return 0;
}
没有预处理的,dfs枚举每一行
代码(16MS):
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define nMAX 13
#define ll __int64
#define MAX (1<<12)
#define MOD 100000000
using namespace std;
ll dp[nMAX][MAX+2];
int map[nMAX][nMAX];
int r,c,i,j;
void dfs(int col,int state)
{
if(col==c) {dp[i+1][state]+=dp[i][j]; return ;}
if(map[i+1][col]==0) {dfs(col+1,state); return ;}//不可以放
if(j&(1<<col)) //上一行放了,不可以放
{
dfs(col+1,state);
}
else
{
if(col==0) dfs(col+1,state+(1<<col));
else if((state&(1<<(col-1)))==0) dfs(col+1,state+(1<<col));//以后涉及位运算的都加()就是了
dfs(col+1,state);
}
}
int main()
{
int k;
while(~scanf("%d%d",&r,&c))
{
for(i=1;i<=r;i++) //空出一行
for(j=0;j<c;j++)
scanf("%d",&map[i][j]);
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(i=0;i<r;i++)
{
for(j=0;j<(1<<c);j++)
{
if(dp[i][j]) dfs(0,0);//0 0表示i+1行左边起第0个,状态为0
}
}
int ans=0;
for(i=0;i<(1<<c);i++)
{
ans=(ans+dp[r][i])%MOD;
}
printf("%d\n",ans);
}
return 0;
}

浙公网安备 33010602011771号