bzoj1854[Scoi2010]游戏

bzoj1854[Scoi2010]游戏

题意:

n个装备,每种装备都有2个属性值,分别用[1,10000]之间的数表示。使用某种装备时,只能使用该装备的某一个属性。并且每种装备最多只能使用一次。攻击boss的装备所使用的属性值必须从1开始连续递增地攻击,才能对boss产生伤害。求最多能连续攻击boss多少次。

题解:

本题竟然用并查集!把每个装备看成1条无向边,当n条边没有组成一个环时,则一共可以得到n-1个属性,如果n条边组成了一个环,则可以得到n个属性。因此可以使用并查集,根据它除了并操作不会改变根节点的性质,用它维护一个vis数组表示第i个属性能否得到,当一条边插入时,如果两个端点不在一个联通块中,就将根节点表示属性小的那个联通块连到大的那个,并将小的联通块根节点的vis置为1,大的不变;如果在一个联通块中,就将该联通块根节点vis置为1。最后枚举一下vis从1到多少均为1就是答案。

注意:因为我的程序是枚举到vis为0的那个值退出,由于属性最大是10000,所以要枚举到10001。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 using namespace std;
 6 
 7 bool vis[20000]; int fa[20000],n;
 8 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
 9 int main(){
10     scanf("%d",&n); inc(i,1,10000)fa[i]=i; memset(vis,0,sizeof(vis));
11     inc(i,1,n){
12         int a,b,x,y; scanf("%d%d",&a,&b); x=find(a); y=find(b);
13         if(x==y)vis[x]=1;else{if(x>y)swap(x,y); fa[x]=y; vis[x]=1;}
14     }
15     inc(i,1,10001)if(!vis[i]){printf("%d",i-1); break;}
16     return 0;
17 }

20160520

原文地址:https://www.cnblogs.com/YuanZiming/p/5732732.html