HDU-1565-方格取数(1)

来源:互联网 发布:ps淘宝详情页字体大小 编辑:程序博客网 时间:2024/05/18 02:56

HDU-1565-方格取数(1)

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

我的第一个状态压缩DP

给你一个n*n的格子的棋盘,每个格子里面有一个非负数,从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大

3

75 15 21

75 15 28

34 70 5

188

对于每一个数字,或取或不取,记1为取该数,0为不取该数,对于每行的数来说,它的状态就可以用一个二进制的数来描述,对于第一行,若果我们取75,21,我们就可以用二进制的5来描述,即101,因为取的数所在的2个格子不能相邻,所以每一行的二进制数不能有相邻的1,再来看列,相邻的两行不能有相邻的,对于两个二进制,也就是两个数相与(&)为0,这样就可以得到当前的行和上一行的关系,dp[i][j]=dp[i-1][k]+sum(j)

dp[i][j]表示第i行在j状态,dp[i-1][k] 表示第i-1行在k状态,sum(j)表示第i行在状态k下所取数的和,当然k&j==0

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>using namespace std;int num[21];int k,st[18800]; //共有k中状态int dp[2][18800];int map[25][25];int n;int max(int x,int y){    return x>y?x:y;}void init1()   //初始化num,n位数2进制数最多有num[n]种{    int i;    num[0]=1;    for(i=1;i<=20;i++)    num[i]=num[i-1]<<1;}int judge(int x){    int end=0;    while(x)    {        if(end==1&&x%2)        return 0;        end=x%2;        x/=2;    }    return 1;}void init2(){    int i;    init1();    k=0;    for(i=0;i<=num[20];i++)    if(judge(i))    st[k++]=i;    //printf("%d\n",k);  //k=17712,这个要事先求出才能知道数组该开多大}int main(){    int i,j,h;    int Max,temp;    init2();    while(scanf("%d",&n)!=EOF)    {        if(n==0)        {            printf("0\n");            continue;        }        for(i=0;i<n;i++)        for(j=0;j<n;j++)        scanf("%d",&map[i][j]);        Max=-1;        memset(dp,0,sizeof(dp));        for(i=0;i<k;i++)  //先算第一行        {            if(st[i]>=num[n])  //n位数2进制数最多有num[n]种            break;            for(j=0;j<n;j++)  //把每种状态的数从右至左相加            if(st[i]&num[j])            dp[0][i]+=map[0][j];            if(dp[0][i]>Max)            Max=dp[0][i];        }        for(i=1;i<n;i++)        {            for(j=0;j<k;j++)            {                if(st[j]>=num[n])                break;                temp=0;                for(h=0;h<n;h++)                if(st[j]&num[h])                temp+=map[i][h];                for(h=0;h<k;h++)                {                    if(st[h]>=num[n])                    break;                    if(!(st[h]&st[j]))                    dp[1][j]=max(dp[1][j],dp[0][h]+temp);                    Max=max(Max,dp[1][j]);                }            }            for(j=0;j<k;j++)            {                if(st[j]>num[n])                break;                dp[0][j]=dp[1][j];                dp[1][j]=0;            }        }        printf("%d\n",Max);    }    system("pause");    return 0;}


原创粉丝点击