1. 程式人生 > >[HNOI2006]超級英雄

[HNOI2006]超級英雄

codec 接下來 struct 可能 原理 更改 std 是我 等於

題目描述

現在電視臺有一種節目叫做超級英雄,大概的流程就是每位選手到臺上回答主持人的幾個問題,然後根據回答問題的多少獲得不同數目的獎品或獎金。主持人問題準備了若幹道題目,只有當選手正確回答一道題後,才能進入下一題,否則就被淘汰。為了增加節目的趣味性並適當降低難度,主持人總提供給選手幾個“錦囊妙計”,比如求助現場觀眾,或者去掉若幹個錯誤答案(選擇題)等等。

這裏,我們把規則稍微改變一下。假設主持人總共有m道題,選手有n種不同的“錦囊妙計”。主持人規定,每道題都可以從兩種“錦囊妙計”中選擇一種,而每種“錦囊妙計”只能用一次。我們又假設一道題使用了它允許的錦囊妙計後,就一定能正確回答,順利進入下一題。現在我來到了節目現場,可是我實在是太笨了,以至於一道題也不會做,每道題只好借助使用“錦囊妙計”來通過。如果我事先就知道了每道題能夠使用哪兩種“錦囊妙計”,那麽你能告訴我怎樣選擇才能通過最多的題數嗎?

輸入輸出格式

輸入格式:

輸入的第一行是兩個正整數 技術分享技術分享 (技術分享)表示總共有 n 種“錦囊妙計”,編號為 技術分享,總共有 技術分享 個問題。

以下的m行,每行兩個數,分別表示第 技術分享 個問題可以使用的“錦囊妙計”的編號。

註意,每種編號的“錦囊妙計”只能使用一次,同一個問題的兩個“錦囊妙計”可能一樣。

輸出格式:

輸出的第一行為最多能通過的題數 技術分享,接下來 技術分享 行,每行為一個整數,第 技術分享 行表示第 技術分享 題使用的“錦囊妙計的編號”。

如果有多種答案,那麽任意輸出一種,本題使用 Special Judge 評判答案。

輸入輸出樣例

輸入樣例#1:
5 6
3 2
2 0
0 3
0 4
3 2
3 2
輸出樣例#1:
4
3
2
0
4

題解:

1.Solution1 二分圖匹配

可以直接上匈牙利,枚舉每一個問題,直到匹配失敗時的問題數就是答案

原理可以認為是匈牙利算法不會使之前的問題失去匹配,而是更改它的匹配對象.

2.Solution2 二分答案+網絡流

直接二分mid,將前mid個問題建立匹配,判斷最大流是否等於mid即可

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7
using namespace std; 8 const int N=2005; 9 int head[N],num=0; 10 struct Lin{ 11 int next,to; 12 }a[N<<1]; 13 void init(int x,int y){ 14 a[++num].next=head[x]; 15 a[num].to=y; 16 head[x]=num; 17 } 18 void addedge(int x,int y){ 19 init(x,y);init(y,x); 20 } 21 int n,m,bel[N];bool vis[N]; 22 bool dfs(int x){ 23 int u; 24 for(int i=head[x];i;i=a[i].next){ 25 u=a[i].to; 26 if(!vis[u]){ 27 vis[u]=true; 28 if(!bel[u] || dfs(bel[u])){ 29 bel[x]=u;bel[u]=x;return true; 30 } 31 } 32 } 33 return false; 34 } 35 void work(){ 36 int x,y; 37 scanf("%d%d",&n,&m); 38 for(int i=1;i<=m;i++){ 39 scanf("%d%d",&x,&y); 40 addedge(i,x+m);addedge(i,y+m); 41 } 42 bool t;int i; 43 for(i=1;i<=m;i++){ 44 memset(vis,0,sizeof(vis)); 45 t=dfs(i); 46 if(!t)break; 47 } 48 i--; 49 printf("%d\n",i); 50 for(int j=1;j<=i;j++) 51 printf("%d\n",bel[j]-m); 52 } 53 int main() 54 { 55 work(); 56 return 0; 57 }

[HNOI2006]超級英雄