●BZOJ 1854 [Scoi2010]遊戲
阿新 • • 發佈:2017-12-08
最大 std 會有 fine can light mar http toolbar
題鏈:
http://www.lydsy.com/JudgeOnline/problem.php?id=1854
題解:
並查集(還可以用匈牙利算法進行單路增廣的二分圖匹配)
把每個武器看成是一條邊,每個傷害值看成是一個點,
那麽每一條邊就連接了兩個點。
並把一條邊e與其一個端點u的“對應”表示為用這個武器e打出傷害u。
對於一個聯通塊,我們考慮把點和邊一一對應,使得被對應的點盡量多。
1).對於一棵樹來說,就會有一個點沒有邊與之對應,令那個點為聯通塊裏編號最大的點。
2).而對於非樹圖來說,即存在環,那麽所有點都可以與一條邊對應。
這樣的話,就可以用並查集維護聯通信息了。做法如下:
對於輸入的 x,y,我們找到其各自所在聯通塊裏編號最大的點(也是根)fx,fy。
如果 fx==fy,那麽表明加入這條邊後這個聯通塊出現了環,則 vis[fx]=1;
否則(令 fx<fy),表明是兩個聯通塊合並了,則讓編號較小的那個(即fx)可以有邊與它對應,vis[fx]=1;
最後從左往右遍歷一遍 vis,找到第一個 i,使得 vis[i]=0,那麽答案即為 i-1。
代碼:
#include<cstdio> #include<cstring> #include<iostream> #define MAXN 1050000 #define filein(x) freopen(#x".in","r",stdin); #define fileout(x) freopen(#x".out","w",stdout); using namespace std; bool vis[MAXN]; int fa[MAXN]; int N; int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); } void merge(int x,int y){ if(x>y) swap(x,y); fa[x]=y; vis[x]=1; } int main() { filein(game); fileout(game); scanf("%d",&N); for(int i=0;i<=1000000;i++) fa[i]=i; for(int i=1,x,y,fx,fy;i<=N;i++){ scanf("%d%d",&x,&y); fx=find(x); fy=find(y); if(fx==fy) vis[fx]=1; else merge(fx,fy); } for(int i=1;i<=1000000;i++) if(!vis[i]){ printf("%d",i-1); break; } return 0; }
●BZOJ 1854 [Scoi2010]遊戲