codevs 1069 关押罪犯

codevs 1069 关押罪犯

  1. 本来想着只需要用sort把这对犯人按怨气值排序即可,然后从大到小把犯人放在不同的监狱里即可,后来才返现我忽视了一个重要问题,比如: a-b c-d ,接下来是b - c , b - d,就是c, d 仓库的方法对后面是有影响的。现在就发现,这个问题我似乎又不知道怎么去思考好了。考虑图形的环状吗?可是maxN = 20000。
  2. 看了题解,发现最好的方法是用并查集做(怎么自己就完全没有想到这个算法呢?太嫩了啊- - )
    代码:

       #include<iostream>
       #include<algorithm>
       using namespace std;
    
       int fa[55555];
    
       struct S {
        int a, b, c;
        friend inline bool operator < (S a, S b) {
            return a.c > b.c;
        }
       } dat[100000];
    
       int find(int x) {
        return fa[x] == x ? x : (fa[x] = find(fa[x]));
       }
    
       int main() {
        int n, m;
        cin >> n >> m;
        for (int i(0); i < m; ++i)
            cin >> dat[i].a >> dat[i].b >> dat[i].c;
        sort(dat, dat + m);
        for (int i(0); i < 2 * n; ++i)
            fa[i] = i;
        for (int i(0); i < m; ++i) {
            int fx(find(dat[i].a)), fy(find(dat[i].b));
            if (fx == fy) {
                cout << dat[i].c << endl;
                return 0;
            }
            fa[fx] = find(dat[i].b + n);
            fa[fy] = find(dat[i].a + n);
        }
        cout << 0 << endl;
        return 0;
       }

    解释:
    用并查集表示每个犯人之间的关系,在同一个集合中则说明两人在同一个监狱,反之则不在同一个监狱。用类似于克鲁斯卡尔的方法,先将边排序,然后按照仇恨值的大小从大到小处理。对于每一组,先看两个人能不能加入不同的集合,
    如果可以,将两人加入不同的集合,如果不可以,则输出该组仇恨值。
    用补集来表示两个点不在一个集合中。如a和b’在同一个集合中,则a和b不在同一个集合中,不能把b直接加入另一个集合,因为会对后面的结果产生影响。
    如,3和4不在同一个集合中,但是我们现在不知道究竟是3在第一个监狱还是4在第一个监狱,所以此时用3和4‘在同一个集合中来表示3和4不在同一个集合中。——转载至http://blog.csdn.net/u013653310/article/details/46792373
    自己的理解:(中午躺在床上半天终于想出来了),首先注意到有这条语句
    int fx(find(dat[i].a)), fy(find(dat[i].b));
    说明fa[x]里面的x可能是(0 ~n,即本身),也可能是(x + n,即它的补集),所以先认清楚一个思维误区,一个集合里面可能有(a+n , e+n,…),他们的联通块编号可能是某个数字,比如(e+n)。在同一个集合里面,所有的正常数字不能和里面的某个补集,比如a+n共存,也就说,所有数字不能和a放在同一个集合。那么a + n 和 e+n 都在的话,说明什么呢?我们可以这样想:既然所有数字都不能和a 一起, 也不能和e一起,而且又只有2个监狱,那么a 只能和 e一起。在这份代码中,只要某2个数字得到的联通快编号一样,说明它们在同一个集合中,就不能再在同一个监狱中,所以就是不合法的了。

  3. 终于想通了~总算懂了补集这个东西。每天进步一点点,万岁!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值