博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UVA1349(带权二分图最大匹配 --> KM算法模板)
阅读量:4597 次
发布时间:2019-06-09

本文共 3172 字,大约阅读时间需要 10 分钟。

UVA1349

题意:给定一些有向带权边,求出把这些边构造成一个个环,总权值最小

解法:

对于带权的二分图的匹配问题可以用通过KM算法求解。

要求最大权匹配就是初始化g[i][j]为0,直接跑就可以;

要求最小权匹配就是初始化g[i][j]为-INF,加边的时候边权为负,最后输出答案的相反数。

 

因为要求每个点恰好属于一个圈,意味着每个点都有一个唯一的后继。 反过来,只要每个点都有唯一的后继,每个点一定属于某个圈。

唯一的是我们想到了二分图的概念,我们对于每个点,建立由u到v的二分图, 之后问题就转换成了二分图上的最小权完美匹配问题

1 #include
2 #define REP(i, a, b) for(int i = (a); i < (b); i++) 3 #define MEM(a,x) memset(a,x,sizeof(a)) 4 #define INF 0x3f3f3f3f 5 #define MAXN 100+10 6 using namespace std; 7 8 struct KM { 9 int n; 10 int g[MAXN][MAXN]; 11 int Lx[MAXN], Ly[MAXN]; 12 int slack[MAXN];//记录距X匹配到Y点还需要多少权值 13 int match[MAXN];//记录每个X点匹配到的Y集中的点 14 bool S[MAXN], T[MAXN]; 15 16 void init(int n) { 17 this->n = n; 18 for (int i = 0; i < n; i++) 19 for (int j = 0; j < n; j++) 20 g[i][j] = -INF; 21 //注意这里如果是求最大权值匹配和就赋值为0 22 //最小权值匹配和就是—INF 23 } 24 25 void add_Edge(int u, int v, int val) { 26 g[u][v] = max(g[u][v], val); 27 } 28 29 bool dfs(int i) { 30 S[i] = true; 31 for (int j = 0; j < n; j++) { 32 if (T[j]) continue; 33 int tmp = Lx[i] + Ly[j] - g[i][j]; 34 if (!tmp) { 35 T[j] = true; 36 if (match[j] == -1 || dfs(match[j])) { 37 match[j] = i; 38 return true; 39 } 40 } 41 else slack[j] = min(slack[j], tmp); 42 } 43 return false; 44 } 45 46 void update() { 47 int a = INF; 48 for (int i = 0; i < n; i++) 49 if (!T[i]) a = min(a, slack[i]); 50 for (int i = 0; i < n; i++) { 51 if (S[i]) Lx[i] -= a; 52 if (T[i]) Ly[i] += a; 53 } 54 } 55 56 void km() { 57 for (int i = 0; i < n; i++) { 58 match[i] = -1; 59 Lx[i] = -INF; Ly[i] = 0; 60 for (int j = 0; j < n; j++) 61 Lx[i] = max(Lx[i], g[i][j]); 62 } 63 for (int i = 0; i < n; i++) { 64 for (int j = 0; j < n; j++) slack[j] = INF; 65 while (1) { 66 for (int j = 0; j < n; j++) S[j] = T[j] = false; 67 if (dfs(i)) break; 68 else update(); 69 } 70 } 71 } 72 }Men; 73 74 int main() { 75 int n; 76 while (scanf("%d", &n) == 1 && n) { 77 Men.init(n); 78 REP(u, 0, n) { 79 int v; 80 while (scanf("%d", &v) && v) { 81 int w; scanf("%d", &w); 82 v--; 83 Men.add_Edge(u, v, -w); 84 } 85 } 86 87 Men.km(); 88 int ans = 0, flag = 1; 89 REP(i, 0, n) { 90 if (Men.g[Men.match[i]][i] == -INF) { 91 //有未匹配到,就是不成功,因为题目要求的是完美匹配 92 flag = 0; 93 break; 94 } 95 ans += Men.g[Men.match[i]][i];//累加权值 96 } 97 if (!flag) printf("N\n"); 98 else printf("%d\n", -ans);//最后是输出的是负数 99 }100 return 0;101 }

 

转载于:https://www.cnblogs.com/romaLzhih/p/9572059.html

你可能感兴趣的文章
183. Customers Who Never Order--solution
查看>>
贝叶斯如何生效
查看>>
UVA - 1588 - Kickdown
查看>>
Win32 SDK:ListBox 为什么不整个 LB_SETTEXT
查看>>
spring的优缺点
查看>>
优云老王的心路历程(一):那个做了五年的产品经理
查看>>
双态运维分享之:业务场景驱动的服务型CMDB
查看>>
cocos2dx-3.6 触摸,键盘,聚焦事件
查看>>
JEECG中t:dictSelect的extendJson用法
查看>>
web开发下的各种下载方法
查看>>
第六章 堆排序 6.5 优先队列
查看>>
Linux搭建我的世界服务器
查看>>
数据库之范式
查看>>
译文 [ROM][多国语言][2015.06.11] Lenovo S750 (MTK6589) - andrea_d86-lenovos750-4.2.2
查看>>
租用游艇问题
查看>>
如何修改SharePoint 2010默认的任务通知邮件的格式?
查看>>
单用户模式下连接被占用定位spid
查看>>
Django JWT
查看>>
云推送注意(MSDN链接)
查看>>
八圆包如何在互联网产品丛林中成为九块九包邮集市领跑者?
查看>>