AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1854
[分析]
我们将每个武器看作一条边,分别连接两个权值。
因为对于每个点的数量为n的联通块,当它没有环的时候,最多只有其中的n-1个点能够符合条件;
而对于有环的联通块,其n个点都能够符合条件。
我们设vis[i]表示权值i能否符合条件,则当联通块没有环的时候,只有权值最大的点的vis为false,而其他的点的vis都为true;
当联通块有环的时候,所有的点vis都为true。
如何实现这一点呢?若题目中的两个权值不在同一个集合中时,将代表员小的合并进代表员大的,将代表员小的vis设为false;
若它们在同一个集合中,则其代表员的vis也设为false;
这样就可以保证前面的条件。最后只要for一遍vis数组就可以了。
注意:因为答案可能为10000,所以要for到10001。
具体实现方法见代码:
#include <iostream> #include <cstdio> using namespace std; int n; int fa[1000010]; bool vis[1000010]; int find(int x){ int tmp=x,pre; while(tmp!=fa[tmp])tmp=fa[tmp]; while(x!=tmp){ pre=fa[x]; fa[x]=tmp; x=pre; } return tmp; } void merge(int x,int y){ int fx=find(x),fy=find(y); if(fx>fy){ int t=fx; fx=fy; fy=t; } vis[fx]=true; fa[fx]=fy; } int main(){ scanf("%d",&n); for(int i=1;i<=10001;i++)fa[i]=i; for(int i=1;i<=n;i++){ int x,y; scanf("%d%d",&x,&y); if(find(x)==find(y))vis[find(x)]=true; else merge(x,y); } for(int i=1;i<=10001;i++)if(!vis[i]){printf("%d\n",i-1);break;} return 0; }