首页 > 代码库 > hdu 1565 方格取数(1) (状态压缩+dp)

hdu 1565 方格取数(1) (状态压缩+dp)

方格取数(1)

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5589    Accepted Submission(s): 2123


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

Input
包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20)
 

Output
对于每个测试实例,输出可能取得的最大的和
 

Sample Input
3 75 15 21 75 15 28 34 70 5
 

Sample Output
188
 

思路:枚举每个状态,得到最优解。枚举上下两个状态时,应判断它们之间是否矛盾,用一个二进制数可以记录每一行的一种取法,即相邻的两位的数字不能都为1,间隔取数。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 21
#define M 30000
int state[M];
int a[N][N];
int dp[N][M];
int n,lim;
void inti()  //得到一行能取的数的所有集合
{            //每个数组元素代表一种取法
    int i,k;
    for(i=k=0;i<=(1<<20);i++)
    {
        if(i&(i<<1))  //每个数字左移一位,若与自身相与为真
            continue; //这个数字肯定有相邻两位都为1.
        state[k++]=i; //i=1101 ,左移一位后为ii=11010 ,
    }
}
int getsum(int i,int x)  //得到该种取法的数组和
{                        
    int t,sum;
    t=sum=0;
    while(x)
    {
        if(x&1)          //相与为真则这个数字能取
            sum+=a[i][t];
        x>>=1;
        t++;
    }
    return sum;
}
void solve()
{
    int i,j,k;
    lim=1<<n;
    for(i=0;state[i]<lim;i++)
    {
        dp[0][i]=getsum(0,state[i]);
    }
    for(i=1;i<n;i++)         //遍历剩下的数组
    {
        for(j=0;state[j]<lim;j++) //对于每一行可取的状态
        {
            int tmp=0;
            for(k=0;state[k]<lim;k++) //找到上一行能取得最大值
            {
                if(!(state[j]&state[k]))  //相邻两行不矛盾
                    tmp=max(tmp,dp[i-1][k]);
            }
            dp[i][j]=tmp+getsum(i,state[j]);
        }
    }
    int ans=0;
    for(i=0;state[i]<lim;i++)
        ans=max(ans,dp[n-1][i]);
    printf("%d\n",ans);
}
int main()
{
    int i,j;
    inti();
    while(scanf("%d",&n)!=-1)
    {
        if(n==0)  //特判
        {
            printf("0\n");
            continue;
        }
        for(i=0;i<n;i++)
        {
            for(j=0;j<n;j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        solve();
    }
    return 0;
}




hdu 1565 方格取数(1) (状态压缩+dp)