1. 程式人生 > >bzoj1854 [Scoi2010]遊戲 二分圖匹配 並查集

bzoj1854 [Scoi2010]遊戲 二分圖匹配 並查集

Description

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

對於30%的資料,保證N < =1000
對於100%的資料,保證N < =1000000

Solution

原來去年做過的單殺lyk可以這樣做(不太記得了)
如果沒有相差為1和從1開始的限制,直接連(ai,i)和(bi,i)求二分圖最大匹配。容易發現順序無關,只要不同即可
具體到這題可以考慮從1開始列舉看是否能找到對應點
有一個trick就是在匈牙利dfs的時候不需要每次清空vis陣列,直接用時間戳標記會快很多

另一種做法參考自黃學長,對於一個武器看成一條邊(a,b)
若一個連通塊有n個點n-1條邊(一棵樹)則一定有一個點不能被取到
若一個連通塊有n個點至少n條邊,則任意一個點都能被取到
顯然我們讓一個連通塊中最大的點不能被取是最優的。合併的時候記錄一下,求答案的時候掃一遍即可

但是這樣做是有問題的,即一個有自環的點連在了樹上(畫圖腦補一下)的時候會錯,那麼離線所有的武器然後強行把ab相同的武器排在後面

Code

匈牙利做法

#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define max(x,y) ((x)>(y)?(x):(y))
const int N=1000005;
const int E=2000005;
struct
edge{int y,next;}e[E]; int link[N],ls[N],edCnt=0; int vis[N]; int read() { int x=0,v=1; char ch=getchar(); for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar()); for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar()); return x*v; } void addEdge(int x,int y) {e[++edCnt]=(edge){y,ls[x]}; ls[x]=edCnt;} int find(int now,int id) { for (int i=ls[now];i;i=e[i].next) { if (vis[e[i].y]==id) continue; vis[e[i].y]=id; if (!link[e[i].y]||find(link[e[i].y],id)) { link[e[i].y]=now; return 1; } } return 0; } int main(void) { freopen("data.in","r",stdin); freopen("std.out","w",stdout); int n=read(),mx=0; rep(i,1,n) { int x=read(),y=read(); mx=max(mx,x); mx=max(mx,y); addEdge(x,i); addEdge(y,i); } int ans=0; rep(i,1,mx) { if (find(i,i)) ans++; else break; } printf("%d\n", ans); return 0; }

並查集做法

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define max(x,y) ((x)>(y)?(x):(y))
using std:: swap;
const int N=1000005;
int rank[N],fa[N],vis[N],x[N],y[N];
int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}
int get_father(int now) {return (!fa[now])?(now):(fa[now]=get_father(fa[now]));}
void merge(int x,int y) {
    x=get_father(x); y=get_father(y);
    if (x>y) swap(x,y); vis[x]=1;
    if (x!=y) fa[x]=y;
}
bool cmp(int a,int b) {return x[a]!=y[a]&&x[b]==y[b];}
int main(void) {
    int n=read(),mx=0;
    rep(i,1,n) {
        x[i]=read(),y[i]=read();
        rank[i]=i;
    }
    std:: sort(rank+1,rank+n+1,cmp);
    rep(ti,1,n) {
        int i=rank[ti];
        mx=max(mx,x[i]); mx=max(mx,y[i]);
        merge(x[i],y[i]);
    }
    int ans;
    rep(i,1,mx+1) if (!vis[i]) {
        ans=i-1;
        break;
    }
    printf("%d\n", ans);
}

相關推薦

bzoj1854 [Scoi2010]遊戲 二分匹配

Description lxhgww最近迷上了一款遊戲,在遊戲裡,他擁有很多的裝備,每種裝備都有2個屬性,這些屬性的值用[1,10000]之間的數表示。當他使用某種裝備時,他只能使用該裝備的某一個屬性。並且每種裝備最多隻能使用一次。 遊戲進行到最後,lxh

BZOJ 1854: [Scoi2010]遊戲 二分匹配

lxhgww最近迷上了一款遊戲,在遊戲裡,他擁有很多的裝備,每種裝備都有2個屬性,這些屬性的值用[1,10000]之間的數表示。當他使用某種裝備時,他只能使用該裝備的某一個屬性。並且每種裝備最多隻能使用一次。 遊戲進行到最後,lxhgww遇到了終極boss,這個終極boss很奇怪,攻擊他的裝備所使用的屬性值

【bzoj 1854】[Scoi2010]遊戲 二分匹配

http://blog.csdn.net/pbihao/article/details/52835849 額,感覺像是一道題改一下就好了 #include<cstdio> #inclu

Codeforces 776D.The Door Problem (dfs二分判定 / )

二分圖染色 space find inline lin rem amp 屬於 兩個 題目鏈接: http://codeforces.com/problemset/problem/776/D 題意: n扇門,m個開關(n,m<=1e5),每個開關控制若幹個門,反轉開關門

BZOJ 4025 二分 分治+

題目大意:給定一張n個點的圖,有m條邊,T個時間段,每條邊只存在於(st,ed]這些時間段,求每個時間段內這個圖是否是二分圖 分治並查集大法好 定義Solve(x,y,E)為當前處理的區間為[x,y],E為所有存在時間為[x,y]的子集的邊的集合 那麼對於

BZOJ 1854 SCOI2010 遊戲 二分最大匹配/

題目大意:給定n個武器,每個武器有兩個屬性,只能使用其中一個,要求選擇一些武器 可以造成形如1 2 3 4的傷害 求最大傷害 題目大意我沒寫明白還是去看原題把QAQ 做法1: 同 1191 每個武器向兩個屬性連邊 然後從1~10000列舉屬性 跑二分圖最大匹配 無法匹配則輸

[luogu1640 SCOI2010]連續攻擊遊戲 (二分匹配)

() oss ring ems put printf class names 表示 [傳送門] (https://www.luogu.org/problemnew/show/P1640) Description lxhgww最近迷上了一款遊戲,在遊戲裏,他擁有很多的裝備,每

bzoj 1854: [Scoi2010]遊戲(二分的最大匹配)

1854: [Scoi2010]遊戲 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 3695  Solved: 1405 [Submit][Status][Discuss] Description lxhgww最近迷上了

[bzoj1059] [ZJOI2007] 矩陣遊戲 (二分匹配)

output efi 一個 否則 == 不變 答案 fin ostream 小Q是一個非常聰明的孩子,除了國際象棋,他還很喜歡玩一個電腦益智遊戲——矩陣遊戲。矩陣遊戲在一個N *N黑白方陣進行(如同國際象棋一般,只是顏色是隨意的)。每次可以對該矩陣進行兩種操作:行交換操作:

bzoj1059: [ZJOI2007]矩陣遊戲(二分匹配)

AI .com str php print 組成 line ems set 1059: [ZJOI2007]矩陣遊戲 題目:傳送門 題解:    為了趕上蘇大佬的光速的腳步...刷了題水題,不過蘇大佬好像一早就搞定了,所以也沒有什麽關系了對吧!    其實說水題的

BZOJ 1059 矩陣遊戲 二分匹配

不可 false 外掛 space 象棋 對角線 sizeof 決定 blank 題目鏈接: https://www.lydsy.com/JudgeOnline/problem.php?id=1059 題目大意: 小Q是一個非常聰明的孩子,除了國際象棋,他還很喜歡玩一個電腦

洛谷P1640 連續攻擊遊戲+二分匹配

本題是個二分圖匹配問題。首先我們來複習一下匈牙利演算法:用臨接矩陣寫的匈牙利:Code:(洛谷P3386) #include<iostream> #include<algorithm> #include<cstdio> #include<cstring>

BZOJ [ZJOI2007]矩陣遊戲(二分匹配)

1059: [ZJOI2007]矩陣遊戲 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 6390  Solved: 3133[Submit][Status][Discus

1059: [ZJOI2007]矩陣遊戲 二分匹配

1059: [ZJOI2007]矩陣遊戲 二分圖匹配 2016年11月14日 11:42:46 閱讀數:136   1059: [ZJOI2007]矩陣遊戲 Time Limit: 10 Sec  Memory Limit: 16

$bzoj1059-ZJOI2007$矩陣遊戲 二分匹配

交換 顏色 dfs int mat 子圖 關系 象棋 algo 題面描述 小\(Q\)是一個非常聰明的孩子,除了國際象棋,他還很喜歡玩一個電腦益智遊戲——矩陣遊戲。矩陣遊戲在一個\(N*N\)黑白方陣進行(如同國際象棋一般,只是顏色是隨意的)。每次可以對該矩陣進行兩種操

51nod1307(暴力樹剖/二分&dfs/)

href 存在 stdio.h cto pda long void 最大 amp 題目鏈接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1307 題意: 中文題誒~ 思路: 解法1:暴

[BZOJ3237][AHOI2013]連通(分治)

break freopen spa width eight line sca rip urn 3237: [Ahoi2013]連通圖 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1736 Solved: 655[S

【hiho】14 無間道之論--

const lse string turn problem scan -c for sca 傳送門:無間道之並查集 分析 並查集的分析可以看上面的傳送門,寫的挺好的了。 其實在我看來並查集就是一種方便的維護集合的一種技巧,提出了代表元素這一概念。 My AC Code #i

Newcoder 39 D.加邊的無向

Description 給你一個 n n n 個點,

HDU 6350 2018HDU多校賽 第五場 Always Online(論 + + 組合計數)

          大致題意:給你一個仙人掌圖,讓你計算:。 根據去年多校賽某一道題的經驗,很多仙人掌圖的問題,其實可以轉化為樹的問題。所以我們同樣考慮,如果這是一棵樹的話如何去做。注意到表示式裡面的flow(i,j)表示從i到j的最小割或最大流,而在樹上的最小