SCOI2010(HYSBZ1854)“遊戲”

題目:HYSBZ - 1854

lxhgww最近迷上了一款遊戲,在遊戲裏,他擁有很多的裝備,每種裝備都有2個屬性,這些屬性的值用[1,10000]之間的數表示。當他使用某種裝備時,他只能使用該裝備的某一個屬性。並且每種裝備最多隻能使用一次。 遊戲進行到最後,lxhgww遇到了終極boss,這個終極boss很奇怪,攻擊他的裝備所使用的屬性值必須從1開始連續遞增地攻擊,才能對boss產生傷害。也就是說一開始的時候,lxhgww只能使用某個屬性值爲1的裝備攻擊boss,然後只能使用某個屬性值爲2的裝備攻擊boss,然後只能使用某個屬性值爲3的裝備攻擊boss……以此類推。 現在lxhgww想知道他最多能連續攻擊boss多少次?
分析:

怎麼又是遊戲。。。SCOI的出題人是有多喜歡遊戲。。。

咳,回到正題,不得不說這是一道較神的題,不是說它題有多厲害,而是黃學長的的解法很神,居然是並查集(以我這種蒟蒻的殘缺腦回路是絕對想不出的。。。。)
首先我們將每一個屬性值看做一個點,然後把每一把武器看做一條連接兩點的邊。我們將所有的邊連起來後可以得到的是一個有若干個樹或者環的圖。
對於每一個大小爲n的一棵樹來說,我們只能選擇其中n-1個屬性值,按照題意,應該優先選擇編號較小n-1個點;
對於每一個大小爲n的環來說,我們可以全部選擇n個屬性值。
則我們可以用並查集來實現:每有一條邊,我們就合併兩端點a,b,這裏我們定義對於一個並查集樹,除了它的根是還沒有選擇的,其他子節點都選過了,則有兩種情況:
1.若a的根x不等於b的根y,則說明我們x和y這兩個屬性值從來沒有選擇過,按照優先選擇小(假設是x)的來說,我們將x的打上選擇標記,並將x併到y的上去,當然如果這裏的x已經有標記了,就把y打上標記就行了。
2.若a的根x等於b的根y,則說明x,y中較小的已經有選擇標記,則我就只需將較大的打上標記就行了。
最後枚舉標記,看在哪個地方斷開,答案就是多少。
沒想到黃學長的代碼還有錯。。。

代碼:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cctype>
using namespace std;
int fa[1000001],n,a,b,vis[1000001];
int read()
{
	char ch=getchar();
	int k=1,res=0;
	while(!isdigit(ch)){if(ch=='-') k=-1;ch=getchar();}
	while(isdigit(ch)){res=res*10+ch-'0';ch=getchar();}
	return res*k;
}
int find(int x)
{
	if(fa[x]==x)return x;
	return fa[x]=find(fa[x]);
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=10001;i++) fa[i]=i;
	for(int i=1;i<=n;i++)
	{
		scanf("%d %d",&a,&b);
		if(a>b) swap(a,b);
		a=find(a),b=find(b);
		if(a==b) vis[b]=1;
		else
		{
			fa[a]=b;
			if(!vis[a]) vis[a]=1;
			else vis[b]=1;
		} 
		
	}
	for(int i=1;i<=n+1;i++)
	if(!vis[i]) {
		printf("%d",i-1);
		break;
	}
 	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章