您的位置:首页 > 大数据 > 人工智能

匈牙利算法 (poj1422-Air Raid,poj1469-COURSES)

2009-07-13 08:55 477 查看
首先注意区分“最小路径覆盖”(minimum path cover)和“最小边覆盖”(minimum edge cover)以及“最小点覆盖”(minimum vertex cover)之间的区别。详细资料可以查询Wiki。

最小路径覆盖可以转化为二分图的最大匹配(maximum bipartite matching) 。公式为最小路径覆盖数=原图节点数-二分图最大匹配数。

求最大匹配的方法有两种:一是将二分图增添两个节点(source起点和sink终点)构造一个流网络(flow network),然后就可以按求最大流的算法来计算,基本的算法有Ford-Fulkerson算法。不过这样实现起来比较麻烦,下面着重介绍第二种方法:匈牙利算法(Hungarian algorithm )

匈牙利算法其实和基于增广路径(augmenting path)的最大流算法是比较相似的。不同点在于:

  一,匈牙利算法不需要构造流网络,也就是说不需要增添节点,并且二分图是无向图,不需要转换为流网络中的有向图。

  二,匈牙利算法的增广路径(设为P)有附加条件:P的第一条边必须是尚未匹配的边,第二条边是已经匹配的边,如此未匹配和已匹配的边交替出现,最后一条边仍然是未匹配边(注意P可以是只有一条未匹配边的路径)。根据增广路径的附加条件可以看出一个特点:P的未匹配边一定比已匹配边多一条。

  三,匈牙利算法依次对二分图的半边(左半边或者右半边,条件是节点数少的一边)的每个节点开始找增广路径,如果找到则取反:未匹配的边变成匹配边,已匹配边去掉匹配关系。这样的结果是路径P的匹配边数量增加一条,未匹配边数量减少一条。寻找增广路径的方法为DFS或者BFS递归。

  四,当二分图中不存在增广路径时即产生最大匹配数。

匈牙利算法的实质就是找增广路径,并对增广路径做取反操作,直到没有增广路径为止。

匈牙利算法的基本流程:

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #define GSIZE 251
5
6 typedef struct{
7     int queue[GSIZE];
8     int head;
9     int tail;
10 }QUEUE;
11
12 int vtx, eg;
13 QUEUE q;
14 int color[GSIZE], par[GSIZE];
15 int resNet[GSIZE][GSIZE];    //模拟链表:y轴为节点索引,每一行存放此节点指向的节点索引,
16                             //若为-1则说明指向的节点为空
17 int InitQueue(){
18     q.head=q.tail=0;
19     return 1;
20 }
21 int EnQueue(int x){
22     q.queue[q.tail]=x;
23     q.tail++;
24     return 1;
25 }
26 int DeQueue(){
27     int x;
28     x=q.queue[q.head];
29     q.head++;
30     return x;
31 }
32
33 int BFSFindPath()
34 {
35     int flag, i, u, v;
36     flag=0;
37     InitQueue();
38     for (i=1;i<=vtx;i++){
39         color[i]=color[i+120]=0;
40         par[i]=par[i+120]=-1;
41     }
42     color[250]=0;
43     par[250]=-1;
44     color[0]=1;
45     par[0]=-1;
46     EnQueue(0);
47     while (q.head!=q.tail && flag==0){
48         u=DeQueue();
49         i=0;
50         while (resNet[u][i]!=-1 && resNet[u][i]!=0 && i<GSIZE){
51             v=resNet[u][i];
52             if (color[v]==0){
53                 color[v]=1;
54                 par[v]=u;
55                 EnQueue(v);
56             }
57             if (v==250){//当搜索到一条最短路径后停止
58                 flag=1;
59                 break;
60             }
61             i++;
62         }
63         color[u]=2;
64     }
65     return flag;
66 }
67 int Ford_Fulkerson()
68 {
69     int pathNum, v, i, del;
70     pathNum=0;
71     while (BFSFindPath()){
72         v=250;
73         //par[v]---->v修改为v--->par[v]
74         while (par[v]!=-1){
75             i=0;
76             while (resNet[v][i]!=-1 && i<GSIZE){
77                 i++;
78             }
79             resNet[v][i]=par[v];
80             i=0;
81             while (resNet[par[v]][i]!=-1 && i<GSIZE){
82                 if (resNet[par[v]][i]==v){
83                     del=i;
84                 }
85                 i++;
86             }
87             resNet[par[v]][del]=resNet[par[v]][i-1];
88             resNet[par[v]][i-1]=-1;
89
90             v=par[v];
91         }
92         pathNum++;
93     }
94     return pathNum;
95 }
96 int main()
97 {
98     int c, i, st, end, cnt, ans;
99     //freopen("input.txt", "r", stdin);
scanf("%d", &c);
while (c--){
memset(resNet, -1, sizeof(resNet));
scanf("%d %d", &vtx, &eg);
//设起点下标0,终点下标250,构造剩余网络
for (i=1;i<=vtx;i++){
resNet[0][i-1]=i;
resNet[i+120][0]=250;
}
for (i=1;i<=eg;i++){
cnt=0;
scanf("%d %d", &st, &end);
while (resNet[st][cnt]!=-1){
cnt++;
}
resNet[st][cnt]=end+120;
}
if (eg==0){
ans=vtx;
}
else{
ans=vtx-Ford_Fulkerson();
}
printf("%d\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: