ZOJ3471状压DP

3 篇文章 0 订阅

题目链接:https://www.nowcoder.com/acm/contest/116/J

有n个原子,任意两个原子互相撞击会产生一定的能量,并且被撞击的那个会消失,然后要你求当n个原子发生了n-1次撞击后能产生的最大能量.

输入:包含多组实例.每个实例的第一行是N(2<=N<=10),然后接下来N行,每行有N个整数x(0<=x<=1000),第i行的第j个数,表示i原子撞击j原子后产生的能量,且j消失.当N为0时表输入结束.

输出:对于每个实例输出能量最大值.

分析:本题和TSP问题很相似,使用类似的状态定义方式解即可.

令d[i][S]表示当前在原子i且已经用过的原子集合为S(S包括i)时,能产生的最大能量.

状态转移方程是:d[i][S|(1<<i)]=max{ d[j][S]+v[i][j] },用i去撞j,或d[j][S|(1<<i)]=max{d[j][S]+v[j][i] },用j去撞i

初值:d[i][1<<i]=0.

这么做此题就是错的.题意理解有偏差:本题的意思是任意两个原子都可以相撞,并不一定是要依次相撞.比如6个原子,现在123原子已经撞了剩下3号原子,接下来我可以用5和6撞,然后再用剩下的去撞3,而并不一定需要用3去撞{4,5,6}中的一个.所以正确的解法应该是:

令d[S]=x表示当前集合S中表示的原子已经销毁了,能产生的最大能量值.

d[S+{j}]=max{ d[S]+v[i][j] },i与j都是集合S外的原子且用i撞j.

d[S+{i}]=max{ d[S]+v[j][i] },i与j都是集合S外的原子且用j撞i.

代码:

#include <bits/stdc++.h>
 
using namespace std;
 
const vector<int> v {1,2,4,8,16,32,64,128,256,512,1024,2048};
int main()
{
    int n;
    while(scanf("%d", &n) && n) {
        vector<vector<int> >e (n, vector<int>(n));
        for(int i = 0;i < n;i ++) for(int j = 0;j < n;j ++) scanf("%d", &e[i][j]);
        vector<int>dp(v[n], 0);
        for(int i = 0;i < v[n];i ++) {
            for(int j = 0;j < n;j ++) {
                if(i & v[j]) continue;
                for(int k = 0;k < n;k ++) {
                    if(k != j && !( i & v[k] ) ) {
                        dp[i | v[j]] = max(dp[i | v[j]], dp[i] + e[k][j]);
                    }
                }
            }
        }
        int res = 0;
        for(int i = 0;i < v[n];i ++) res = max(res, dp[i]);
        printf("%d\n", res);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值