您的位置:首页 > 其它

状态压缩DP——hdu 1565 方格取数1

2013-07-16 15:39 239 查看
题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1565

题目大意:

中文题目,不解释

解题思路:

由于每行最多是20个格子,取的格子不能相邻,最多的状态数在18000左右,可以用状态压缩来做。

状态转移方程:

 dp[i][j]=max(dp[i-1][k]+date[i][j],dp[i][j]);

dp[i][j]: 第i行取第j个状态的时候的最大值

date[i][j]:第i行取第j个状态的时候可以增加的值

源代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int dp[21][40000];         //到第i行时,状态为j的时候取得的最大值
int state[40000];
int n;
int Map[21][21];
int date[21][40000];        //第i行状态为j的时候取得数值大小
int cnt;                    //有效状态的总个数
int ok1(int x)              //对于第一行,判断状态i是否是合法的
{
int j;
while(x>0)
{
if(x%2==1)
{
if((x>>1)%2==1)
return 0;
}
x/=2;
}
return 1;
}
int cal(int i,int j)        //已知第i行和第j个状态,求取可以得到多少值
{
int sum,k,t;
sum=0;
t=state[j];
for(k=0;k<n;k++)    //枚举位数
{
if((t&(1<<k)))  //第k位是1
{
sum+=Map[i][k];
}
}
return sum;
}
void init()    //对状态进行找出所有的有效状态
{
int i,temp;
temp=(1<<n);
cnt=0;
memset(dp,0,sizeof(dp));
for(i=0;i<temp;i++)
{
if(ok1(i))
{
state[cnt++]=i;
}
}
//printf("%d\n",cnt);
return;
}
int main()
{
//freopen("in.txt","r",stdin);
int i,j,k,t;
while(scanf("%d",&n)==1)
{
if(n==0)
{
printf("0\n");
continue;
}
memset(Map,0,sizeof(Map));
init();
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
scanf("%d",&Map[i][j]);
}
}
memset(date,0,sizeof(date));
for(i=0;i<n;i++)        //枚举行数
{
for(j=0;j<cnt;j++)  //枚举第j个状态
{
date[i][j]=cal(i,j);
}
}
memset(dp,0,sizeof(dp));
//初始化第0行
for(j=0;j<cnt;j++)  //枚举状态
{
dp[0][j]=date[0][j];
}
for(i=1;i<n;i++)        //枚举行
{
for(j=0;j<cnt;j++)  //枚举当前行的第j个状态
{
for(k=0;k<cnt;k++)  //枚举上一行的第k个状态
{
if((state[j]&state[k])==0)    //状态j和状态k是兼容的
dp[i][j]=max(dp[i-1][k]+date[i][j],dp[i][j]);
}
}
}
int Max=0;
for(i=0;i<cnt;i++)
{
Max=max(Max,dp[n-1][i]);
}
printf("%d\n",Max);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: