【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 }