[hdu2167]Pebbles

Description

给你一个N*N(3<=N<=15)个矩阵,要你选择若干个数(每个数的范围在[10,99]),使得最后所选的数总和最大。选数的规则是如果选了某个数,那么它的八个相邻方向的数都不能选。

Sample Input

71 24 95 56 54
85 50 74 94 28
92 96 23 71 10
23 61 31 30 46
64 33 32 95 89

78 78 11 55 20 11
98 54 81 43 39 97
12 15 79 99 58 10
13 79 83 65 34 17
85 59 61 12 58 97
40 63 97 85 66 90

33 49 78 79 30 16 34 88 54 39 26
80 21 32 71 89 63 39 52 90 14 89
49 66 33 19 45 61 31 29 84 98 58
36 53 35 33 88 90 19 23 76 23 76
77 27 25 42 70 36 35 91 17 79 43
33 85 33 59 47 46 63 75 98 96 55
75 88 10 57 85 71 34 10 59 84 45
29 34 43 46 75 28 47 63 48 16 19
62 57 91 85 89 70 80 30 19 38 14
61 35 36 20 38 18 89 64 63 88 83
45 46 89 53 83 59 48 45 87 98 21

15 95 24 35 79 35 55 66 91 95 86 87
94 15 84 42 88 83 64 50 22 99 13 32
85 12 43 39 41 23 35 97 54 98 18 85
84 61 77 96 49 38 75 95 16 71 22 14
18 72 97 94 43 18 59 78 33 80 68 59
26 94 78 87 78 92 59 83 26 88 91 91
34 84 53 98 83 49 60 11 55 17 51 75
29 80 14 79 15 18 94 39 69 24 93 41
66 64 88 82 21 56 16 41 57 74 51 79
49 15 59 21 37 27 78 41 38 82 19 62
54 91 47 29 38 67 52 92 81 99 11 27
31 62 32 97 42 93 43 79 88 44 54 48

Sample Output

572
683
2096
2755

通过这道题,我第一次学习了状态压缩DP。
状压DP是指将一大串只有两种状态的东西转成2进制基础上进行的DP。
这道题,可以用状压。
设dp[i][x]为第i行,一定用x这种方案1~i为合法方案。
先求出一行内合法的状态。
然后枚举行数i,再枚举该行状态x,然后再枚举方案y与当前状态是否合法,DP方程如下:
DP[i][x]=max(DP[i][x],DP[i-1][y]+sum);
(sum为x这种方案的总和)

代码虽丑,不要吐槽!!!

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int f[16][1<<15];
int a[16][16],v[1<<15],vn,bin[16],n;
char s[110000];
int mymax(int x,int y){return x>y?x:y;}
int main()
{
    bin[1]=1;for(int i=2;i<=15;i++)bin[i]=bin[i-1]<<1;
    while(scanf("%d",&a[1][1])!=EOF)
    {
        n=1;
        char c;scanf("%c",&c);
        while(c!='\n')
        {
            n++;
            scanf("%d",&a[1][n]);
            scanf("%c",&c);
        }
        for(int i=2;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&a[i][j]);
        getchar();
        int maxx=(1<<n)-1;
        vn=0;
        memset(f,0,sizeof(f));
        for(int x=0;x<=maxx;x++)
        {
            if(((x<<1)&x)==0)
            {
                for(int i=1;i<=n;i++)
                {
                    if((bin[i]&x))
                    {
                        f[1][x]+=a[1][i];
                    }
                }
                v[++vn]=x;
            }
        }
        for(int i=2;i<=n;i++)
        {
            for(int p=1;p<=vn;p++)
            {
                int tt=0;for(int j=1;j<=n;j++)if(bin[j]&v[p])tt+=a[i][j];
                for(int q=1;q<=vn;q++)
                {
                    if((v[p]&v[q])==0&&(v[q]<<1&v[p])==0&&(v[q]>>1&v[p])==0)
                    {
                        f[i][v[p]]=mymax(f[i][v[p]],tt+f[i-1][v[q]]);
                    }
                }
            }
        }
        int ans=0;for(int i=1;i<=vn;i++)ans=mymax(ans,f[n][v[i]]);
        printf("%d\n",ans);
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值