过山车(二分图匹配)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2063
hdu_2063:过山车
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 14852 Accepted Submission(s): 6544
Problem Description
RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了。可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生做partner和她同坐。但是,每个女孩都有各自的想法,举个例子把,Rabbit只愿意和XHD或PQK做partner,Grass只愿意和linle或LL做partner,PrincessSnow愿意和水域浪子或伪酷儿做partner。考虑到经费问题,boss刘决定只让找到partner的人去坐过山车,其他的人,嘿嘿,就站在下面看着吧。聪明的Acmer,你可以帮忙算算最多有多少对组合可以坐上过山车吗?
Input
输入数据的第一行是三个整数K , M , N,分别表示可能的组合数目,女生的人数,男生的人数。0<K<=1000
1<=N 和M<=500.接下来的K行,每行有两个数,分别表示女生Ai愿意和男生Bj做partner。最后一个0结束输入。
1<=N 和M<=500.接下来的K行,每行有两个数,分别表示女生Ai愿意和男生Bj做partner。最后一个0结束输入。
Output
对于每组数据,输出一个整数,表示可以坐上过山车的最多组合数。
Sample Input
6 3 3
1 1
1 2
1 3
2 1
2 3
3 1
0
Sample Output
3
Author
PrincessSnow
Source
题解: 一道标准的二分图匹配,但是要注意二分图中左边和右边的点不能有重复的编号,所以如果左边的点是从0开始编号到m-1的话,男生要从m开始编号
匈牙利算法的思路是用到递归的调用,这里每次找到一条增广路后都要将虚实线对调,所以这种找到解再对之前的路径进行操作的行为叫做回溯,回溯的语句一定要写成下面的形式:
if(找到解)
{
回溯操作;//这里只是考虑最上面一个操作就可以了,假设后面的通过递归已经都解决了,类似于dfs的思路
}
所以找路径的核心代码就是:
if(rm[s]==-1||find(rm[s]))
{
rm[s] = s;
return 1;//返回找到了
}
下面给出代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define N 1010 6 int head[N]; 7 struct Edge{ 8 int to; 9 int next; 10 }edge[N*N]; 11 int Enct; 12 void init() 13 { 14 memset(head,-1,sizeof(head)); 15 Enct = 0; 16 } 17 void add(int from , int to) 18 { 19 edge[Enct].to = to; 20 edge[Enct].next = head[from]; 21 head[from] = Enct++; 22 edge[Enct].to = from; 23 edge[Enct].next = head[to]; 24 head[to] = Enct++; 25 } 26 bool vis[N*N]; 27 int k , n , m ; 28 int rm[N*N]; 29 30 bool list(int s) 31 { 32 for(int j = head[s] ; j != -1 ; j = edge[j].next) 33 { 34 int tm = edge[j].to; 35 if(vis[tm]==1) continue; 36 vis[tm] = 1;//记得标记为未访问 37 if(rm[tm]==-1||list(rm[tm])){ 38 rm[tm] = s; 39 return 1; 40 } 41 } 42 return 0; 43 } 44 int MaxMatch() 45 { 46 int ans = 0; 47 for(int i = 0 ; i < m ; i++) 48 { 49 memset(vis,0,sizeof(vis)); 50 vis[i] = 1;//要标记刚进入的点是未访问的 51 if(list(i)) ans++; 52 } 53 return ans; 54 } 55 int main() 56 { 57 while(~scanf("%d%d%d",&k,&m,&n)) 58 { 59 init(); 60 for(int i = 0 ;i < k ;i++) 61 { 62 int x, y; 63 scanf("%d%d",&x,&y); 64 add(x-1,y+m-1);//他们构成了一张图,所以不可以让两个点有相同的编号 65 } 66 int a ; 67 scanf("%d",&a); 68 memset(rm,-1,sizeof(rm)); 69 int ans = MaxMatch(); 70 printf("%d\n",ans); 71 } 72 return 0; 73 }