BZOJ 1854[Scoi2010]游戏
2016-01-23 16:24
337 查看
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。
具体实现方法见代码:
[分析]
我们将每个武器看作一条边,分别连接两个权值。
因为对于每个点的数量为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; }
相关文章推荐
- (八)Android广播接收器BroadcastReceiver
- Elmah 日志记录组件
- 关于innodb purge thread和master thread
- hibernate对象关系实现(三)多对多实现
- IO流 改变标准输入输出设备
- 2016年1月23日 后台生成HTML table 传到前台页面
- 【PA2015】【BZOJ4292】Równanie
- jasime 单元测试
- 进一步解 apt-get 的几个命令
- 代码约束2
- C++使用priority_queue方法
- Numpy之random模块
- 运行page页面时的事件执行顺序
- Android 开发中常用 ADB 命令总结
- java中protected的权限
- JZWC【Day2】题解&总结
- kafka设计要点
- iOS-数据归档
- MVC模型
- Linux监控介绍