初学匈牙利算法(一)
推荐参考的基础资料:
百度百科_增广路:http://baike.baidu.com/view/3585026.htm
百度百科_二分图匹配:http://baike.baidu.com/view/501087.htm
百度百科_匹配:http://baike.baidu.com/view/352573.htm
以上参考中的基础及定义不再赘述
一。匈牙利算法有关概念
这是一种用增广路求二分图最大匹配的算法。它由匈牙利数学家Edmonds于1965年提出,因而得名。
未盖点:设Vi是图G的一个顶点,如果Vi 不与任意一条属于匹配M的边相关联,就称Vi 是一个未盖点。
交错路:设P是图G的一条路,如果P的任意两条相邻的边一定是一条属于M而另一条不属于M,就称P是一条交错路。
可增广路:两个端点都是未盖点的交错路叫做可增广路。
二。流程图
三。裸代码(矩阵存储)
1 program hungary;
2 var
3 i,j,n,m,ans,x,y,l,k:longint;
4 a:array[1..1000,1..1000]of boolean;
5 b:array[1..1000]of longint;
6 c:array[1..1000]of boolean;
7 function pd(x:longint):boolean;
8 var
9 i,j:longint;
10 begin
11 for i:=1 to n do
12 if (a[x,i])and(not c[i]) then
13 begin
14 c[i]:=true;
15 if(b[i]=0)or(pd(b[i])) then
16 begin
17 b[i]:=x;
18 exit(true);
19 end;
20 end;
21 exit(false);
22 end;
23
24 procedure hungary;
25 var
26 i,j:longint;
27 begin
28 fillchar(b,sizeof(b),0);
29 for i:=1 to m do
30 begin
31 fillchar(c,sizeof(c),0);
32 if pd(i) then inc(ans);
33 end;
34 end;
35
36 begin
37 assign(input,'hungary.in');
38 reset(input);
39 readln(m,n,k);
40 for i:=1 to k do
41 begin
42 readln(x,y);
43 a[x,y]:=true;
44 a[y,x]:=true;
45 end;
46 ans:=0;
47 hungary;
48 writeln(ans);
49 close(input);
50 end.
四。例题一个
Dormitory
【题目描述】
小蛮妹子有许多的,什么棉花糖啦,蜥蜴啊,小乌龟啊,只有你想不到的没有她没有的。
小蛮妹子的小宠物都住在一个漂亮的大屋子里,每个人都有自己的床位,但是由于小蛮妹子的宠物太多了,以至于这些宠物之间并不是都互相认识。
这些宠物们也有自己的朋友,这些朋友一直羡慕他们住的漂亮大屋子,于是有一天,小蛮妹子出去玩了,一些小宠物也偷偷出去玩了,那些留守的小宠物们开始招待来访的客人。
这些来客都打算在这里住一晚上,可是安排床位就出了麻烦。每个小宠物都只愿意在自己的直接朋友或自己的床上(如果它是小蛮的宠物)睡觉,且一物睡一张床。
询问是否能有一个方案来满足所有在留宿的宠物都能住宿。
【输入格式】
第一行一个数 T 表示数据组数。
接下来 T 组数据。
每组数据第一行一个数 n 表示涉及到的总宠物数(包括小蛮的宠物和来客)。
接下来一行 n 个数,第 i 个数表示第 i 个个宠物是否是在小蛮的宠物 (0 表示不是,1 表示是)。再接下来一行 n 个数,第 i 个数表示第 i 个人是否出去玩(0 表示不出去,1 表示出去)注意如果第 i 个人不是小蛮的宠物,那么这个位置上的数是一个随机的数,你应该在读入以后忽略它)。
接下来 n 行,每行 n 个数,第 i 行第 j 个数表示 i 和 j 是否认识 (1 表示认识,0 表示不认识,第 i 行 i 个的值为 0,但是显然自己还是可以睡自己的床),认识的关系是
相互的。
【输出格式】
每一行对应每组数据
若存在方案满足条件 输出 ^.^ ,否则输出 T.T (只有三个字符,没有空格等其他内容)
【输入样例】
1
3
1 1 0
0 1 0
0 1 1
1 0 0
1 0 0
【输出样例】
^.^
【数据hint】
对于 30% 的数据满足 1 ≤ n ≤ 12。
对于 100% 的数据满足 1 ≤ n ≤ 50,1 ≤ T ≤ 20。
解析:
显然的是二分图匹配,不解释
难度主要在预处理部分,
然后直接用匈牙利就行了。粘代码:
1 program dormitory;
2 var
3 i,j,n,bj,m,k,l,ans,r,bb,z:longint;
4 a:array[1..100,1..100]of longint;
5 b,c,v:array[1..100]of longint;
6 function pd(x:longint):boolean;
7 var
8 i,j:longint;
9 begin
10 for i:=1 to 100 do
11 if (a[x,i]=1)and(c[i]=0) then
12 begin
13 c[i]:=1;
14 if (b[i]=0)or(pd(b[i])) then
15 begin
16 b[i]:=x;
17 exit(true);
18 end;
19 end;
20 exit(false);
21 end;
22
23 procedure hungary;
24 var
25 i,j:longint;
26 begin
27 fillchar(b,sizeof(b),0);
28 for i:=1 to n do
29 begin
30 fillchar(c,sizeof(c),0);
31 if pd(i) then inc(ans);
32 end;
33 if ans>=z then writeln('^.^')
34 else writeln('T.T');
35 end;
36
37 begin
38 assign(input,'dormitory.in');
39 reset(input);
40 assign(output,'dormitory.out');
41 rewrite(output);
42 readln(l);
43 for i:=1 to l do
44 begin
45 fillchar(a,sizeof(a),0);
46 fillchar(b,sizeof(b),0);
47 fillchar(c,sizeof(c),0);
48 readln(n);
49 ans:=0;z:=0;
50 for j:=1 to n do read(b[j]);
51 for j:=1 to n do begin read(c[j]);if ((b[j]=1)and(c[j]=0))or(b[j]=0) then inc(z);end;
52 for j:=1 to n do
53 begin
54 for k:=1 to n do
55 begin
56 read(r);
57 if r=1 then begin a[j,k+50]:=1;a[k+50,j]:=1;end;
58 end;
59 readln;
60 end;
61 for j:=1 to n do begin a[j,j+50]:=1;a[j+50,j]:=1;end;
62 for j:=1 to n do
63 if b[j]=0 then
64 for k:=1 to 50 do begin a[k,j+50]:=0;a[j+50,k]:=0;end;
65 for j:=1 to n do
66 if c[j]=1 then
67 for k:=51 to 100 do begin a[j,k]:=0;a[k,j]:=0;end;
68 hungary;
69 end;
70 close(input);
71 close(output);
72 end.
引用:
Beyond the Void的博客:http://www.byvoid.com/blog/