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:最少時,每個中轉站至少有一個入點和一個出點

  

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

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

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

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

CODE

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

  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;
}