【NOIP2010】关押罪犯

一道感觉不错的并查集的题目

我们先将每一组矛盾关系按照冲突值从大到小排序,然后顺序扫描一遍,让冲突值大的两个人尽可能不在一个监狱里,如果不能满足,那么答案就是这组关系的矛盾值。如果所有的矛盾都不会发生,那么答案就是0.

之后我们建立并查集,另外定义一个辅助的数组d表示每一个人的一个敌人。我们扫描每一对关系,如果这两个人为了满足前面的条件已经在同一所监狱,那么答案就是他们的冲突值。否则,我们检查这两个人分别于对方的敌人合并即可。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 typedef long long ll;
 7 struct node {
 8     int a,b,c;
 9     bool operator <(const node &x) const {
10         return c<x.c;
11     }
12 }aa[100010];
13 int n,m;
14 int f[100010],d[100010];
15 int find(int x) {
16     if(f[x]!=x) return f[x]=find(f[x]);
17     return f[x];
18 }
19 void add(int x,int y) {
20     int fx=find(x);
21     int fy=find(y);
22     f[fy]=fx;
23 }
24 int main() {
25     scanf("%d%d",&n,&m);
26     for(int i=1;i<=n;i++) f[i]=i;
27     for(int i=1;i<=m;i++) {
28         scanf("%d%d%d",&aa[i].a,&aa[i].b,&aa[i].c);
29     }
30     sort(aa+1,aa+m+1);
31     reverse(aa+1,aa+m+1);
32     for(int i=1;i<=m;i++) {
33         if(find(aa[i].a)==find(aa[i].b)) {
34             printf("%d\n",aa[i].c);
35             return 0;
36         }
37         if(!d[aa[i].a]) d[aa[i].a]=aa[i].b;
38         else add(aa[i].b,d[aa[i].a]);
39         if(!d[aa[i].b]) d[aa[i].b]=aa[i].a;
40         else add(aa[i].a,d[aa[i].b]);
41     }
42     puts("0");
43     return 0;
44 }
AC Code

 

posted @ 2019-05-25 12:52  AD_shl  阅读(205)  评论(0编辑  收藏  举报