[bzoj1854][Scoi2010]遊戲【並查集】【貪心】
阿新 • • 發佈:2019-01-31
【題目描述】
Description
lxhgww最近迷上了一款遊戲,在遊戲裡,他擁有很多的裝備,每種裝備都有2個屬性,這些屬性的值用[1,10000]之間的數表示。當他使用某種裝備時,他只能使用該裝備的某一個屬性。並且每種裝備最多隻能使用一次。 遊戲進行到最後,lxhgww遇到了終極boss,這個終極boss很奇怪,攻擊他的裝備所使用的屬性值必須從1開始連續遞增地攻擊,才能對boss產生傷害。也就是說一開始的時候,lxhgww只能使用某個屬性值為1的裝備攻擊boss,然後只能使用某個屬性值為2的裝備攻擊boss,然後只能使用某個屬性值為3的裝備攻擊boss……以此類推。 現在lxhgww想知道他最多能連續攻擊boss多少次?Input
Output
輸出一行,包括1個數字,表示lxhgww最多能連續攻擊的次數。Sample Input
31 2
3 2
4 5
Sample Output
2HINT
【資料範圍】
對於30%的資料,保證N < =1000
對於100%的資料,保證N < =1000000
Source
【題解】
第一眼看這道題以為是迭代的網路流,但有更妙的貪心演算法。
考慮並查集,把每個裝備當做一條邊,如果存在一個聯通塊是樹,那麼一定是剩下編號最大的一個不選,如果不是樹,那麼能全部去完。
合併時,如果是兩棵樹,剩下編號大的,取編號小的。否則都能取完。
複雜度 O(n α n)
/* -------------- user Vanisher problem bzoj-1854 ----------------*/ # include <bits/stdc++.h> # define ll long long # define N 10010 using namespace std; int read(){ int tmp=0, fh=1; char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();} while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();} return tmp*fh; } int f[N],n,u,v,can[N]; int dad(int u){ if (f[u]==u) return u; else return f[u]=dad(f[u]); } int main(){ n=read(); for (int i=1; i<=N-1; i++) f[i]=i; for (int i=1; i<=n; i++){ u=read(), v=read(); u=dad(u), v=dad(v); if (u==v) can[u]=true; else { if (u>v) swap(u,v); if (can[u]==true) can[v]=true; else can[u]=true; f[u]=v; } } for (int i=1; i<=N-1; i++) if (can[i]==false) { printf("%d\n",i-1); return 0; } return 0; }