1. 程式人生 > WINDOWS開發 >yesky wine供應系統題解【二分圖匹配】

yesky wine供應系統題解【二分圖匹配】

4513: yesky wine供應系統

Time Limit:1 SecMemory Limit:128 MB
Submit:34Solved:6

Description

自從上次懶羊羊紅酒促銷會後,越來越多的羊族及朋友喜歡上了yesky wine。懶羊羊跟葉老師申請要銷售更多的yesky wine紅酒。為此,他還準備改造他的紅酒供應系統。紅酒供應系統由一個酒廠,一個紅酒儲藏站,若干供應站和管道組成。當然,酒廠就位於葉老師所在的浙江理工大學後花園。中轉站位於懶羊羊開設的很多酒吧、餐廳和其他紅酒供應場所,需要時可以銷售。紅酒儲藏站的位置非常神祕,不過這個對整個系統不是很重要。
紅酒供應管道連線了剛才提到的各站點。酒廠至少連線了1個站點,神祕的儲藏站也至少連線了一個站點。當然,極端的情況下,可能酒廠直接連線到神祕的儲藏站,而沒有其他任何中轉站。

從酒廠出來的紅酒通過管道充滿了(經常是)一些站點並且能自動流到下一站點。
紅酒在系統裡流動,從某個站點流出的紅酒不會返回到該站點,也就是說系統中不會出現迴路。管道中酒的流向也是固定的不會迴流。酒廠的酒是足夠的,管道中的經常是有紅酒流的。
現在的紅酒供應系統有一些管道是多餘的。你需要對這些管道進行優化,去掉一些多餘的管道使得每個中轉站都能得到紅酒供應,同時也能流轉到神祕的儲藏站。當然,管道的容量是足夠大的。
給你這個供酒系統的佈置圖,你能幫懶羊羊看看最多可以去掉多少根管道嗎?

Input

第一行輸入2個整數N,M(1<=N<=2000,0<=M<=5000),N是系統中紅酒站點,包括酒廠和儲藏站。M是管道數量。站點用1,2,...N標記。

接下來是M行,每行2個整數X和Y,標記著管道是從X流向Y(1<=x,y<=N),資料保證每個管道連線的2個站點是獨一無二的,也不會流向自己。只有一個站點是沒有流進去的,那就是酒廠,也只有一個站點是沒有流出的,那就是神祕的儲藏站。

Output

輸出一個整數,表示可以去掉多餘的最大管道數

Sample Input

【樣例輸入1】
5 6
2 4
3 5
2 5
1 4
2 3
5 1
【樣例輸入2】
4 4
1 2
1 3
2 4
3 4

Sample Output

【樣例輸出1】
2
【樣例輸出2】
0

HINT

Source

2020年浙江理工大學校賽

思路

  感覺這才是本場簽到題,可惜被C搞了心態沒看題

  這道題給人的感覺就是要往二分圖上想

  給出一個有源有匯的有向無環圖,問如何用最少的邊把整張圖跑滿

  因為題目保證了能流滿(∵系統中有多餘的管道)

  在此前提下,僅需要保證圖在最少的連邊情況下跑通即可

  何為最少:刪去一條邊則有站點未被經過,可以看做是未達到最大流

  那麼可得到 要求1:最少時,每個中轉站至少有一個入點和一個出點

  技術分享圖片

  我們通過觀察可以發現,此時求最大流的過程就相當於每兩個中轉站之間去架設管道匹配

  為了方便操作,我們使用匈牙利演算法來計算必須參與匹配的管道數

  對於沒有達到要求1的中轉站,我們把他本來連線的但此時暫未選入的管道加入網路中,來保證我們的圖可以跑通

CODE

技術分享圖片
  1 #include <bits/stdc++.h>
  2 #define dbg(x) cout << #x << "=" << x << endl
  3 #define eps 1e-8
  4 #define pi acos(-1.0)
  5   
  6 using namespace std;
  7 typedef long long LL;
  8   
  9 template<class T>inline void read(T &res)
 10 {
 11     char c;T flag=1;
 12     while((c=getchar())<0||c>9)if(c==-)flag=-1;res=c-0;
 13     while((c=getchar())>=0&&c<=9)res=res*10+c-0;res*=flag;
 14 }
 15   
 16 const int maxn = 2e3 + 5;
 17 const int inf = 0x3f3f3f3f;
 18  
 19 int n,m,e;
 20 int vis[maxn][maxn];
 21 int ask[maxn];
 22 int cnt,ans;
 23 int matched[maxn];
 24 int in1[maxn],out1[maxn];//匹配後每個點出入度
 25 int in[maxn],out[maxn];//匹配前每個點的出入度
 26  
 27 bool fid(int x) {
 28     for (int i = 1 ; i <= n; i++)
 29       if (vis[x][i]) {
 30         if (ask[i])
 31             continue;
 32         ask[i] = 1;
 33         if (!matched[i] || fid(matched[i])) {
 34             matched[i] = x ;
 35             in1[i]++;
 36             out1[x]++;
 37             return true;
 38         }
 39     }
 40     return false;
 41 }
 42  
 43 void match() {
 44     cnt = 0;
 45     memset(matched,0,sizeof(matched));
 46     for(int i = 1; i <= n; ++i) {
 47         memset(ask,sizeof(ask));
 48         if(fid(i)) {
 49             cnt++;
 50         }
 51     }
 52     ans = cnt;
 53 }
 54  
 55  
 56  
 57 int main()
 58 {
 59     read(n); read(m);
 60     cnt = 0;
 61     for(int i = 1; i <= m; i++) {
 62         int x,y;
 63         read(x); read(y);
 64         in[y]++;
 65         out[x]++;
 66         vis[x][y] = 1;
 67     }
 68     match();
 69     // for ( int i = 1; i <= n; ++i ) {
 70     //     printf("match[%d]:%d\n",i,matched[i]);
 71     // }
 72     // puts("");
 73     for ( int i = 1; i <= n; ++i ) {
 74         //printf("out1[%d]:%d in1[%d]:%d\n",out1[i],in1[i]);
 75         if(in[i] && !out[i]) {//T
 76             if(in1[i] == 0) {
 77                 in1[i] = 1;
 78                 ++ans;
 79             }
 80             continue;
 81         }
 82         if(!in[i] && out[i]) {
 83             if(out1[i] == 0) {
 84                 out1[i] = 1;
 85                 ++ans;
 86             }
 87             continue;
 88         }
 89         if(in[i] && out[i]) {
 90             if(in1[i] == 0) {
 91                 ++ans;
 92                 in1[i] = 1;
 93             }
 94             if(out1[i] == 0) {
 95                 ++ans;
 96                 out1[i] = 1;
 97             }
 98             continue;
 99         }
100     }
101     cout << m - ans << endl;
102     //printf("%d\n",ans);
103      
104     return 0;
105 }
View Code

#include<bits/stdc++.h> #definedbg(x)cout<<#x<<"="<<x<<endl #defineeps1e-8 #definepiacos(-1.0) usingnamespacestd; typedeflonglongLL; template<classT>inlinevoidread(T&res) { charc;Tflag=1; while((c=getchar())<‘0‘||c>‘9‘)if(c==‘-‘)flag=-1;res=c-‘0‘; while((c=getchar())>=‘0‘&&c<=‘9‘)res=res*10+c-‘0‘;res*=flag; } constintmaxn=2e3+5; constintinf=0x3f3f3f3f; intn,e; intvis[maxn][maxn]; intask[maxn]; intcnt,ans; intmatched[maxn]; intin1[maxn],out1[maxn];//匹配後每個點出入度 intin[maxn],out[maxn];//匹配前每個點的出入度 boolfid(intx){ for(inti=1;i<=n;i++) if(vis[x][i]){ if(ask[i]) continue; ask[i]=1; if(!matched[i]||fid(matched[i])){ matched[i]=x; in1[i]++; out1[x]++; returntrue; } } returnfalse; } voidmatch(){ cnt=0; memset(matched,0,sizeof(matched)); for(inti=1;i<=n;++i){ memset(ask,sizeof(ask)); if(fid(i)){ cnt++; } } ans=cnt; } intmain() { read(n);read(m); cnt=0; for(inti=1;i<=m;i++){ intx,y; read(x);read(y); in[y]++; out[x]++; vis[x][y]=1; } match(); //for(inti=1;i<=n;++i){ //printf("match[%d]:%d\n",matched[i]); //} //puts(""); for(inti=1;i<=n;++i){ //printf("out1[%d]:%din1[%d]:%d\n",in1[i]); if(in[i]&&!out[i]){//T if(in1[i]==0){ in1[i]=1; ++ans; } continue; } if(!in[i]&&out[i]){ if(out1[i]==0){ out1[i]=1; ++ans; } continue; } if(in[i]&&out[i]){ if(in1[i]==0){ ++ans; in1[i]=1; } if(out1[i]==0){ ++ans; out1[i]=1; } continue; } } cout<<m-ans<<endl; //printf("%d\n",ans); return0; }