过山车(二分图匹配)

题目连接: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结束输入。
 
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
",ans);
71     }
72     return 0;
73 }
原文地址:https://www.cnblogs.com/shanyr/p/4893986.html