SGU 206 Roads KM算法 匹配模型的转化
2012-08-12 16:11
225 查看
这是一道非常好的题目
题目大意:
给了一个图,n个点,m条边,其中前n-1条边保证是生成树,现在你可以修改每条边的边权,花费为修改量,然后用最小的花费修改使得前n-1条边为最小生成树
这题乍一看无从下手
实际上可以这么分析
边可以分为两类,一种是前n-1条边,构成了一个生成树,其他的边是另外一种边
显然如果我们要达到最小生成树的目的,就要让生成树上的边变小,而另外的边变大
从第n条边到第m条边,每条边如果加入那个生成树中,必然会构成了一个环,而我们不想让这条边去替换环中的任意一条边,所以这条边必须比任意环中的边要大。
假设环中的某边为i,这条边为j, 权值分为w[i], w[j] ,修改后的权值为 w[i] - x[i] , w[j] + x[j] 必然有 w[i] - x[i] <= w[j] + x[j] 从而有 x[i] + x[j] >= w[i] - w[j]
然后目的是sum(x[i]) 1 <= i <= m 最小
观察x[i] + x[j] >= w[i] - w[j] 这个不等式和我们的目的,是否发现跟KM算法有相像之处?
因为由可行点标的的定义,图中的任意一个完全匹配,其边权总和均不大于所有点的标号之和,而仅由可行边组成的完全匹配的边权总和等于所有点的标号之和
而我们在寻找可行边的过程,每条边从不是可行边到变为可行边,会使边两端的可行顶标之和减小,最后到达最大权匹配时就是顶标和最小的时候。
这道题又像我们传达了一个算法活用的思想。
往往根据几个式子,就可以转化为某个模型。这也是建立在对算法的深刻理解上吧、
注意:如果两边点数不知谁大谁小,点数少的那一方补齐点,补的点跟另一方的点的边权都为0,KM是先保证的最大匹配数,再保证的最大权
题目大意:
给了一个图,n个点,m条边,其中前n-1条边保证是生成树,现在你可以修改每条边的边权,花费为修改量,然后用最小的花费修改使得前n-1条边为最小生成树
这题乍一看无从下手
实际上可以这么分析
边可以分为两类,一种是前n-1条边,构成了一个生成树,其他的边是另外一种边
显然如果我们要达到最小生成树的目的,就要让生成树上的边变小,而另外的边变大
从第n条边到第m条边,每条边如果加入那个生成树中,必然会构成了一个环,而我们不想让这条边去替换环中的任意一条边,所以这条边必须比任意环中的边要大。
假设环中的某边为i,这条边为j, 权值分为w[i], w[j] ,修改后的权值为 w[i] - x[i] , w[j] + x[j] 必然有 w[i] - x[i] <= w[j] + x[j] 从而有 x[i] + x[j] >= w[i] - w[j]
然后目的是sum(x[i]) 1 <= i <= m 最小
观察x[i] + x[j] >= w[i] - w[j] 这个不等式和我们的目的,是否发现跟KM算法有相像之处?
因为由可行点标的的定义,图中的任意一个完全匹配,其边权总和均不大于所有点的标号之和,而仅由可行边组成的完全匹配的边权总和等于所有点的标号之和
而我们在寻找可行边的过程,每条边从不是可行边到变为可行边,会使边两端的可行顶标之和减小,最后到达最大权匹配时就是顶标和最小的时候。
这道题又像我们传达了一个算法活用的思想。
往往根据几个式子,就可以转化为某个模型。这也是建立在对算法的深刻理解上吧、
注意:如果两边点数不知谁大谁小,点数少的那一方补齐点,补的点跟另一方的点的边权都为0,KM是先保证的最大匹配数,再保证的最大权
#include <iostream> #include <algorithm> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <queue> #include <map> #include <set> #define eps 1e-5 #define MAXN 405 #define MAXM 405 #define INF 100000007 using namespace std; int n, m, ny, nx; int w[MAXN][MAXM]; int lx[MAXN], ly[MAXM]; int linky[MAXM]; int visx[MAXN], visy[MAXM]; int slack[MAXM]; bool find(int x) { visx[x] = 1; for(int y = 1; y <= ny; y++) { if(visy[y]) continue; int t = lx[x] + ly[y] - w[x][y]; if(t == 0) { visy[y] = 1; if(linky[y] == -1 || find(linky[y])) { linky[y] = x; return true; } } else if(slack[y] > t) slack[y] = t; } return false; } int KM() { memset(linky, -1, sizeof(linky)); for(int i = 1; i <= nx; i++) lx[i] = -INF; memset(ly, 0, sizeof(ly)); for(int i = 1; i <= nx; i++) for(int j = 1; j <= ny; j++) if(w[i][j] > lx[i]) lx[i] = w[i][j]; for(int x = 1; x <= nx; x++) { for(int i = 1; i <= ny; i++) slack[i] = INF; while(true) { memset(visx, 0, sizeof(visx)); memset(visy, 0, sizeof(visy)); if(find(x)) break; int d = INF; for(int i = 1; i <= ny; i++) if(!visy[i]) d = min(d, slack[i]); if(d == INF) return -1; for(int i = 1; i <= nx; i++) if(visx[i]) lx[i] -=d; for(int i = 1; i <= ny; i++) if(visy[i]) ly[i] += d; else slack[i] -= d; } } return 1; } int x[MAXN], y[MAXN], z[MAXN]; int g[MAXN][MAXN]; int dfs(int pre, int u, int v, int id) { if(u == v) return 1; for(int i = 1; i <= n; i++) { if(pre == i || !g[u][i]) continue; if(dfs(u, i, v, id)) { w[g[u][i]][id] = z[g[u][i]] - z[id]; return 1; } } return 0; } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= m; i++) scanf("%d%d%d", &x[i], &y[i], &z[i]); for(int i = 1; i <= n - 1; i++) g[x[i]][y[i]] = g[y[i]][x[i]] = i; for(int i = 1; i <= m; i++) for(int j = 1; j <= m; j++) w[i][j] = 0; nx = ny = m; for(int i = n; i <= m; i++) dfs(0, x[i], y[i], i); KM(); for(int i = 1; i < n; i++) printf("%d\n", z[i] - lx[i]); for(int i = n; i <= m; i++) printf("%d\n", z[i] + ly[i]); return 0; }
相关文章推荐
- Uva10795 新汉诺塔问题(转化模型,经典题)
- 关系模型和对象模型的究竟匹配还是不匹配?
- 关于torque3d的模型dts格式转化为o…
- JZOJ4829. 【GDOI2017模拟10.30】独木桥 根据性质转化模型后二分答案
- OpenCV在jni中使用混合高斯背景模型出现的通道匹配错误
- 零基础学python-17.3 特定的参数匹配模型快速入门
- 1:n联系到关系模型的转化
- Java 日期模型匹配
- MeshLab的ply模型转化为Ogre所需的mesh模型(二)
- 块匹配模型
- 区间dp模型(石子归并,括号匹配,整数划分)
- iOS_Runtime6_字典转化为模型应用
- 如何将Sql server数据库中的模型图转化到Word中--并能够查看字段的属性信息
- python数据结构 栈的应用——符号匹配,进制转化,后缀。
- DSSM, 深度语义匹配模型
- 网站转化渠道模型与转化阻力的分析
- hdu1350——Taxi Cab Scheme——————【最小路径覆盖、最大匹配转化】
- Keras模型的加载和保存、预训练、按层名匹配参数
- 激光笔交互之坐标映射算法:匹配点提取和参数模型
- [jzoj]1330. 迎接仪式(转化模型+DP)