1. 程式人生 > >二分圖最大匹配 增廣路徑法實現 pku 1469 COURSES

二分圖最大匹配 增廣路徑法實現 pku 1469 COURSES

註釋在程式碼裡寫的很清楚了

題目:

上程式碼

#include <stdio.h>
#include <memory.h>

//分別定義左右最大元素數量
#define Left_Max 101
#define Right_Max 301

//匹配標誌!!!!!在DFS遍歷中尋找增廣路徑的時候用,每次在尋找增廣路徑的時候都要重新整理
bool visit[Right_Max];
//記錄對應在左邊集合中的元素!!!這個是不要的
int link[Right_Max];
//定義左右集合的連線,1_連線,0_未連線
int map[Left_Max][Right_Max];

int
left_num,right_num; //對於增廣路徑還可以用一個遞迴的方法來描述。這個描述不一定最準確,但是它揭示了尋找增廣路徑的一 //般方法: //“從點A出發的增廣路徑”一定首先連向一個在原匹配中沒有與點A配對的點B。如果點B在原匹配中沒有與 //任何點配對,則它就是這條增廣路徑的終點;反之,如果點B已與點C配對,那麼這條增廣路徑就是從A到B //,再從B到C,再加上“從點C出發的增廣路徑”。並且,這條從C出發的增廣路徑中不能與前半部分的增廣 //路徑有重複的點。 bool find_augment(int left){ for(int i = 1;i <= right_num;i++) //如果右邊集合元素i未被訪問並且left,i可以匹配
if(!visit[i] && map[left][i] != 0){ //標記i已經被匹配 visit[i] = true; //i在左邊還未有標記或者是i在左邊的配對元素能再找一個可以配對的構成增廣路徑 if(link[i] == 0 || find_augment(link[i])){ //link是記錄整個過程中左右元素配對的 //而visit只是在這次的DFS中確定是否存在配對~~~ link[i] = left; return true; } } return false; } int main(){ int
_case; scanf("%d",&_case); int P,N; int i; int count,c,s; while(_case--){ scanf("%d%d",&P,&N); left_num = P; right_num = N; memset(map,0,sizeof(map)); memset(link,0,sizeof(link)); for(c = 1;c <= P;c++){ scanf("%d",&count); for(i = 1;i <= count;i++){ scanf("%d",&s); map[c][s] = 1; } } int ans = 0; for(c = 1;c <= P;c++){ //一次尋找增廣路徑可能要遍歷很多元素,所以都清空 memset(visit,0,sizeof(visit)); if(find_augment(c)) ans++; } if(ans == P) printf("YES/n"); else printf("NO/n"); } return 0; }