二分圖是一個無向圖,分爲x,y兩部分,x部中的點與y中的點每每會存在多條無向邊,若x1與y2之間存在一條邊,那麼x1與y2能夠「分配」,固然每一個點部止侷限於只有一條邊,能夠有多條,因此又有多種分配方法,爲達到讓這個二分圖中分配數量最大,即便x1與y2能夠「分配」也只是暫時的,由於要爲其餘點「讓步」,舉個例子:ios
圖中,點1到點2有一條邊,點1到點3有一條邊,點2到點4有一條邊git
就「擇近原則」,點1能夠首先和點2「分配」,但點3發現本身只有點1能夠「分配」,因而就向點1提出要求「分配」,但是點1已經被「分配過了」,因而點1就去找點2商量問它可不能夠找另外一個點「分配」,點2就去詢問點4可否「分配」,發現點4尚未被「分配」,也就是說點2能夠找另外一個點分配,因而返回true,不和點1「分配」了,和點4分配,點1獲得true便與點3「分配」了算法
細心的人可能會發現,若是像開始那樣:點1與點2分配,那麼只有1個「分配組」,而通過這一系列算法(匈牙利算法)而拓展路線(增廣路)便有2個「分配組」,這就稱爲二分圖最大分配ide
題目連接函數
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 int m; 6 int n; 7 int x,y; 8 int ans; 9 int match[210]; //記錄分配目標 10 int put[110][3]; //輸出 11 bool book[210]; //記錄剪枝 12 bool way[210][210]; //記錄無向圖的邊 13 inline int read() //快速讀入 14 { 15 int sign=1,num=0; 16 char ch=getchar(); 17 while(!isdigit(ch)){if(ch=='-')sign=-1;ch=getchar();} 18 while(isdigit(ch)){num=num*10+(ch-'0');ch=getchar();} 19 return sign*num; 20 } 21 void init() //讀入函數 22 { 23 m=read(); 24 n=read(); 25 while(x!=-1&&y!=-1) 26 { 27 x=read(); //無向邊存兩次 28 y=read(); 29 way[x][y]=true; 30 way[y][x]=true; 31 } 32 } 33 bool dfs(int x) 34 { 35 for(int y=m+n;y>0;--y) 36 { 37 if(way[x][y]&&book[y]==false) //枚舉點x的邊 38 { 39 book[y]=true; //記錄點y已被查找(並不是分配) 40 if(match[y]==0||dfs(match[y])) //若y沒有被分配或與y分配的人還有"退"的餘地 41 { 42 match[x]=y; //儲存分配目標 43 match[y]=x; 44 return true; 45 } 46 } 47 } 48 return false; 49 } 50 int main() //看代碼建議從mian函數看起 51 { 52 init(); 53 for(int i=1;i<=m+n;++i) //枚舉點 54 { 55 memset(book,false,sizeof(book)); 56 dfs(i); 57 } 58 for(int i=1;i<=m+n;++i) 59 if(match[i]!=0&&match[match[i]]!=0) //防止重複輸出 60 { 61 put[++ans][1]=i; 62 put[ans][2]=match[i]; 63 match[match[i]]=0; 64 } 65 if(ans==0) //特判 66 { 67 puts("No Solution!"); 68 return 0; 69 } 70 printf("%d",ans); 71 for(int i=1;i<=ans;++i) 72 printf("\n%d %d",put[i][1],put[i][2]); 73 }