POJ 2531 Network Saboteur(暴力美学)

最近心情不好,而且今天已经wa到哭了,感觉特别悲催!感觉自己的这题的思路还不错,必须来写写博客释放下自己的情绪。

题目大意:有N个节点(0~N-1),给一个邻接矩阵,Cij代表节点i到节点j的花费,其中Cii == 0, Cij == Cji。需要把所有的节点分成A,B两部分,其中的花费就是 ∑Cij (i∈A,j∈B),求最大的花费。(2 <= N <= 20)

解题思路:上午做题的时候没有什么好的思路,但是也想到了怎样去枚举。就是直接用整数来表示集合,那么转换成2进制,如果第i位是0,就表示第i个节点在A集合,否则在B集合。我们来分析下时间复杂度,集合的个数最多是1 << 20,大概是10的6次方多一点,感觉这个时间怎么也不能再少了,然后对于每一个集合,我们的计算大概是N * N,那么这个时间复杂度怎么也通不过。但是,我们仔细思考,如果我们可以把 N * N降成N,那么这道题目大概就能AC了。那么要怎么降低这个时间复杂度呢?其实感觉有点像动态规划或者递推的思想,那就是我们可以保存一下前面的状态,由前面的已经求过的状态通过一个O(N)的复杂度直接推过来。那么问题就迎刃而解了。至于究竟是怎么推的,我已经在代码里面加好注释了,因为涉及到位操作,在这里可能讲不清楚。

Show me the code!

#include <cstdio>
using namespace std;
int N, cost[20][20], s[1 << 20], ans = 0;
int main() {
    scanf("%d", &N);
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            scanf("%d", &cost[i][j]);
        }
    }
    for (int i = 1; i < 1 << N; ++i) {
        int t1 = 0, t2 = 0,
            j = i - (i & -i);//j = i 去掉二进制中最低位的1
        for (int k = 0; k < N; ++k) {//k 是 i 比 j 多的那一位所对应的节点
            for (int l = 0; i - j >> k & 1 && l < N; ++l) {
                //这里嵌套了两个for, 可是内层for只会执行一次, 所以是O(N)的
                if (j >> l & 1) t1 += cost[k][l];
                //t1 = 把第k个节点从一个集合移到另一个集合所减少的花费
                else t2 += cost[k][l];
                //t2 = 把第k个节点从一个集合转移到另一个集合所增加的花费
            }
        }
        //s[i] <<==== s[j]
        s[i] = s[j] - t1 + t2;
        ans = ans > s[i] ? ans : s[i];
    }
    printf("%d\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值