BZOJ 1854 [SCOI2010] 遊戲 並查集

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

輸入描述 Input Description
輸入的第一行是一個整數N,表示lxhgww擁有N種裝備
接下來N行,是對這N種裝備的描述,每行2個數字,表示第i種裝備的2個屬性值

輸出描述 Output Description
輸出一行,包括1個數字,表示lxhgww最多能連續攻擊的次數

樣例輸入 Sample Input
3
1 2
3 2
4 5

樣例輸出 Sample Output
2

數據範圍及提示 Data Size & Hint
對於30% 的數據,保證N1000
對於100% 的數據,保證N1000000

Solution

這個題目有兩種方法都是可做的

  1. 二分圖匹配

這個就很顯然啦
直接將權值和點連邊,按順序刺激110000 的點看是否能形成增廣路,每個點最多刺激一次

  1. 並查集

剛開始知道能用並查集做我是懵逼的
看過HZWERdalao的博客後明白了
將[a,b]的一個物品看做連接[a,b]的一條邊
用並查集維護集合
若一個集合中能夠形成環,則說明集合中的數均可選
若一個集合中沒有環,僅僅爲一棵樹,則說明集合中有一個數選不了
當然我們將集合中最大的數設爲選不了就好了

最後從110000 按順序看每個點所處集合選不了的點是不是他本身即可

代碼如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
int point[N],fa[N],n;
int read() {
    int ans=0,flag=1;
    char ch=getchar();
    while( (ch>'9' || ch<'0') && ch!='-' ) ch=getchar();
    if(ch=='-') {flag=-1;ch=getchar();}
    while(ch>='0' && ch<='9') {ans=ans*10+ch-'0';ch=getchar();}
    return ans*flag;
}
int find(int x) {return fa[x]==x?fa[x]:fa[x]=find(fa[x]);}
int main() {
    n=read();
    for(int i=1;i<=10000;++i) point[i]=fa[i]=i;
    for(int i=1;i<=n;++i) {
        int x=read(),y=read();
        int fx=find(x),fy=find(y);
        if(fx==fy) point[fx]=0;
        else {
            point[fx]=max(point[fx],point[fy]);
            fa[fy]=fx;
        }
    }
    for(int i=1;i<=10000;++i) {
        int fx=find(i);
        if(point[fx]==i) {printf("%d\n",i-1);break;}
        else if(i==10000) printf("%d\n",10000);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章