KM算法 PK 最小费用最大流

用到了KM算法 ,发现自己没有这个模板,搜索学习一下上海大学final大神,http://www.cnblogs.com/kuangbin/p/3228861.html

 

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 #include <iostream>
 5 using namespace std;
 6 
 7 /*  KM算法
 8  *   复杂度O(nx*nx*ny)
 9  *  求最大权匹配
10  *   若求最小权匹配,可将权值取相反数,结果取相反数
11  *  点的编号从0开始
12  */
13 const int N = 310;
14 const int INF = 0x3f3f3f3f;
15 int nx,ny;//两边的点数
16 int g[N][N];//二分图描述
17 int linker[N],lx[N],ly[N];//y中各点匹配状态,x,y中的点标号
18 int slack[N];
19 bool visx[N],visy[N];
20 
21 bool DFS(int x)
22 {
23     visx[x] = true;
24     for(int y = 0; y < ny; y++)
25     {
26         if(visy[y])continue;
27         int tmp = lx[x] + ly[y] - g[x][y];
28         if(tmp == 0)
29         {
30             visy[y] = true;
31             if(linker[y] == -1 || DFS(linker[y]))
32             {
33                 linker[y] = x;
34                 return true;
35             }
36         }
37         else if(slack[y] > tmp)
38             slack[y] = tmp;
39     }
40     return false;
41 }
42 int KM()
43 {
44     memset(linker,-1,sizeof(linker));
45     memset(ly,0,sizeof(ly));
46     for(int i = 0;i < nx;i++)
47     {
48         lx[i] = -INF;
49         for(int j = 0;j < ny;j++)
50             if(g[i][j] > lx[i])
51                 lx[i] = g[i][j];
52     }
53     for(int x = 0;x < nx;x++)
54     {
55         for(int i = 0;i < ny;i++)
56             slack[i] = INF;
57         while(true)
58         {
59             memset(visx,false,sizeof(visx));
60             memset(visy,false,sizeof(visy));
61             if(DFS(x))break;
62             int d = INF;
63             for(int i = 0;i < ny;i++)
64                 if(!visy[i] && d > slack[i])
65                     d = slack[i];
66             for(int i = 0;i < nx;i++)
67                 if(visx[i])
68                     lx[i] -= d;
69             for(int i = 0;i < ny;i++)
70             {
71                 if(visy[i])ly[i] += d;
72                 else slack[i] -= d;
73             }
74         }
75     }
76     int res = 0;
77     for(int i = 0;i < ny;i++)
78         if(linker[i] != -1)
79             res += g[linker[i]][i];
80     return res;
81 }
82 //HDU 2255
83 int main()
84 {
85     int n;
86     while(scanf("%d",&n) == 1)
87     {
88         for(int i = 0;i < n;i++)
89             for(int j = 0;j < n;j++)
90                 scanf("%d",&g[i][j]);
91         nx = ny = n;
92         printf("%d\n",KM());
93     }
94     return 0;
95 }
View Code

 

 

end

转载于:https://www.cnblogs.com/gaolzzxin/p/5597900.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值