信與信封問題
阿新 • • 發佈:2018-12-11
Description
【問題描述】: John先生晚上寫了n封信,並相應地寫了n個信封將信裝好,準備寄出。但是,第二天John的兒子Small John將這n封信都拿出了信封。不幸的是,Small John無法將拿出的信正確地裝回信封中了。 【程式設計任務】: 將Small John所提供的n封信依次編號為1,2,…,n;且n個信封也依次編號為1,2,…,n。假定Small John能提供一組資訊:第i封信肯定不是裝在信封j中。請程式設計幫助Small John,儘可能多地將信正確地裝回信封。
Input
輸入檔案的第一行是一個整數n(n≤100)。信和信封依次編號為1,2,…,n。 接下來的各行中每行有2個數i和j,表示第i封信肯定不是裝在第j個信封中。檔案最後一行是2個0,表示結束。
Output
輸出檔案的每行有2個數i和j,表示第i封信肯定是裝在第j個信封中。請按信的編號i從小到大順序輸出。若不能確定正確裝入信封的任何信件,則輸出“none”。
Sample Input
3
1 2
1 3
2 1
0 0
Sample Output
1 1 二分圖簡單建模。i->j表示i可能在j信封中。樸素的想法是求一遍最大匹配後每次暴力刪邊在做最大匹配,如果小於原答案,則肯定在這個信封中,由於n只有100,完全可過。
事實上,理解了二分圖的這個模型之後,我們只需對其查詢一次增廣路即可。
#include<bits/stdc++.h> using namespace std; const int Maxn=205; int g[Maxn][Maxn]; int n,my[Maxn],mat[Maxn]; bool vst[Maxn]; bool findpath(int x){ for(int i=n+1;i<=n*2;++i)if(g[x][i]&&!vst[i]){ vst[i]=1; if(!my[i]||findpath(my[i])){ my[i]=x; return 1; } } return 0; } int main(){ cin>>n; for(int i=1;i<=n;++i) for(int j=n+1;j<=n*2;++j)g[i][j]=1; int i,j;for(cin>>i>>j;i&&j;cin>>i>>j)g[i][j+n]=0; int ret=0,num=0; for(int i=1;i<=n;++i){ for(int j=n+1;j<=n*2;++j)vst[j]=0; ret+=findpath(i); } for(int i=n+1;i<=n*2;++i)mat[i]=my[i]; for(int x=1;x<=n;++x) for(int y=n+1;y<=n*2;++y)if(my[y]==x){ g[x][y]=0; my[y]=0;//記住這裡要斷 for(int i=n+1;i<=n*2;++i)vst[i]=0; if(!findpath(x))++num,cout<<x<<" "<<y-n<<"\n"; for(int i=n+1;i<=n*2;++i)my[i]=mat[i]; g[x][y]=1; } if(!num)puts("none"); return 0; }