ZOJ-2342 Roads 二分图最小权值覆盖
题意:给定N个点,M条边,M >= N-1。已知M条边都有一个权值,已知前N-1边能构成一颗N个节点生成树,现问通过修改这些边的权值使得最小生成树为前N条边的最小改动总和为多少?
分析:由于计算的最小改动且为最小生成树则显然前N-1条边肯定权值都减少,后面的边权值都增加。由于选择的边为前N-1得到最小生成树,因此首先将N-1条边构图,然后对后面的每一条边,那么这条边所构成的环中,有任意一条边的a与该边b,设原始权重为w[a],w[b],改变量为d[a],w[b],则有w[a] - d[a] <= w[b] + d[b],移项后有w[a] - w[b] <= d[a] + d[b],而我们要求的 d[] 数组的和值的最小值。可以将所有的 d[x] 看作是x节点(边)的权值,则此题相当于给每个节点(边)分配一个权值,使得满足所有环中的不等式,也就是求一个最小权值匹配,其对偶问题就是构图之后的最大权值匹配问题,可行标的值就是需要分配的权值。本题有一个隐含的条件就是d[i] + d[j] >= 0表现在图中就是每个点对之间连了一条权值为0的边,这样才能够保证求出来的值都是正值。
简要分析其原理:首先最大权值匹配算法的初始化就是选择的最大的边设定可行标,且算法在始终不会改变已经匹配边的左右可行标之和的情况下,不停的扩充权值更小的边进入子图,因此其最后得到的最大匹配一定能够保证所有的边左右端点可行标之和大于等于该边权值。其次,如果一个匹配不是最大匹配,那么既然存在最大匹配那么说明肯定有某条本应该在最大匹配中的边没有加入到子图中且该边的左右端点可行标之和小于该边的权值,否则与假设矛盾。
- #include <cstdlib>
- #include <cstring>
- #include <cstdio>
- #include <algorithm>
- using namespace std;
- const int N = ;
- const int M = ;
- const int inf = 0x3f3f3f3f;
- int cn[N][N]; // 原图中的边
- int w[M][M]; // 二分图中边的关系
- int lx[M], ly[M];
- char vx[M], vy[M];
- int match[M];
- int slack[M];
- int n, m, nm;
- struct Edge {
- int a, b, c;
- }e[M];
- bool dfs(int p, int u, int id) {
- for (int i = ; i <= n; ++i) {
- if (i == p) continue;
- if (cn[u][i] == id) return true;
- if (cn[u][i] != && dfs(u, i, id)) {
- w[cn[u][i]][id-(n-)] = max(e[cn[u][i]].c - e[id].c, );
- return true;
- }
- }
- return false;
- }
- bool path(int u) {
- vx[u] = ;
- for (int i = ; i <= nm; ++i) {
- if (vy[i]) continue;
- if (lx[u] + ly[i] == w[u][i]) {
- vy[i] = ;
- if (match[i] == - || path(match[i])) {
- match[i] = u;
- return true;
- }
- } else {
- slack[i] = min(slack[i], lx[u]+ly[i]-w[u][i]);
- }
- }
- return false;
- }
- void KM() {
- memset(match, 0xff, sizeof (match));
- memset(ly, , sizeof (ly));
- memset(lx, 0x80, sizeof (lx));
- for (int i = ; i <= nm; ++i) {
- for (int j = ; j <= nm; ++j) {
- lx[i] = max(lx[i], w[i][j]);
- }
- }
- for (int i = ; i <= nm; ++i) {
- int cnt = ;
- while () {
- memset(slack, 0x3f, sizeof (slack));
- memset(vx, , sizeof (vx));
- memset(vy, , sizeof (vy));
- if (path(i)) break;
- int d = inf;
- for (int j = ; j <= nm; ++j) if (!vy[j]) d = min(d, slack[j]);
- for (int j = ; j <= nm; ++j) if (vx[j]) lx[j] -= d;
- for (int j = ; j <= nm; ++j) {
- if (vy[j]) ly[j] += d;
- else slack[j] -= d;
- }
- }
- }
- }
- int main() {
- int T, a, b, c;
- scanf("%d", &T);
- while (T--) {
- scanf("%d %d", &n, &m);
- memset(cn, , sizeof (cn));
- memset(w, , sizeof (w));
- for (int i = ; i <= m; ++i) {
- scanf("%d %d %d", &a, &b, &c);
- if (i < n) cn[a][b] = cn[b][a] = i;
- e[i].a = a, e[i].b = b, e[i].c = c;
- }
- for (int i = n; i <= m; ++i) {
- cn[e[i].b][e[i].a] = i;
- dfs(, e[i].a, i);
- cn[e[i].b][e[i].a] = ;
- }
- nm = max(n-, m-(n-));
- KM();
- for (int i = ; i < n; ++i) printf("%d\n", e[i].c-lx[i]);
- for (int i = ; i <= m-(n-); ++i) printf("%d\n", e[i+n-].c+ly[i]);
- }
- return ;
- }
ZOJ-2342 Roads 二分图最小权值覆盖的更多相关文章
- HDU 1853 Cyclic Tour[有向环最小权值覆盖]
Cyclic Tour Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/65535 K (Java/Others)Total ...
- POJ 2195 Going Home 【二分图最小权值匹配】
传送门:http://poj.org/problem?id=2195 Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submis ...
- HDU 3488 Tour(最小费用流:有向环最小权值覆盖)
http://acm.hdu.edu.cn/showproblem.php?pid=3488 题意: 给出n个点和m条边,每条边有距离,把这n个点分成1个或多个环,且每个点只能在一个环中,保证有解. ...
- Tour HDU - 3488 有向环最小权值覆盖 费用流
http://acm.hdu.edu.cn/showproblem.php?pid=3488 给一个无源汇的,带有边权的有向图 让你找出一个最小的哈密顿回路 可以用KM算法写,但是费用流也行 思路 1 ...
- POJ-2195 Going Home---KM算法求最小权值匹配(存负边)
题目链接: https://vjudge.net/problem/POJ-2195 题目大意: 给定一个N*M的地图,地图上有若干个man和house,且man与house的数量一致.man每移动一格 ...
- UVa 1349 (二分图最小权完美匹配) Optimal Bus Route Design
题意: 给出一个有向带权图,找到若干个圈,使得每个点恰好属于一个圈.而且这些圈所有边的权值之和最小. 分析: 每个点恰好属于一个有向圈 就等价于 每个点都有唯一后继. 所以把每个点i拆成两个点,Xi ...
- POJ 3565 Ants 【最小权值匹配应用】
传送门:http://poj.org/problem?id=3565 Ants Time Limit: 5000MS Memory Limit: 65536K Total Submissions: ...
- hdu 1853 Cyclic Tour (二分匹配KM最小权值 或 最小费用最大流)
Cyclic Tour Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/65535 K (Java/Others)Total ...
- 紫书 例题11-10 UVa 1349 (二分图最小权完美匹配)
二分图网络流做法 (1)最大基数匹配.源点到每一个X节点连一条容量为1的弧, 每一个Y节点连一条容量为1的弧, 然后每条有向 边连一条弧, 容量为1, 然后跑一遍最大流即可, 最大流即是最大匹配对数 ...
随机推荐
- oracle 数据泵 每天自动备份
@echo off echo 删除10天前的备分文件和日志 forfiles /p "e:\app\back" /m *.dmp /d -5 /c "cmd /c del ...
- java多线程中的生产者与消费者之等待唤醒机制@Version2.0
二.生产者消费者模式的学生类成员变量生产与消费demo, @Version2.0 在学生类中添加同步方法:synchronized get()消费者,synchronized set()生产者 最终版 ...
- Java的深度克隆和浅度克隆
说到克隆,其实是个比较简单的概念,跟现实生活正的克隆一样,复制一个一模一样的对象出来.clone()这个方法是从Object继承下来的,一个对象要实现克隆,需要实现一个叫做Cloneable的接口,这 ...
- Pending Statistics
Starting with the 11g Release 1 (11.1), when gathering statistics, you have the option to automatica ...
- Verilog语法基础讲解之参数化设计
Verilog语法基础讲解之参数化设计 在Verilog语法中,可以实现参数化设计.所谓参数化设计,就是在一个功能模块中,对于一个常量,其值在不同的应用场合需要设置为不同的置,则将此值在设计时使用 ...
- aspnet excel导入导出SQLserver
http://my.csdn.net/libin690145955/code/detail/452 http://blog.csdn.net/ltoper/article/details/532980 ...
- 每日一九度之 题目1038:Sum of Factorials
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2109 解决:901 题目描述: John von Neumann, b. Dec. 28, 1903, d. Feb. 8, 1957, ...
- a different object with the same identifier,同一个session中存在不同的对象问题
使用hibernate的函数 session.merge()函数,提交处于游离态的对象. merge在执行更新之前会将两个标识符相同的对象进行合并,具体合并的方向是向exituser2合并.
- C#中通过Selenium IWebDriver实现人人网相册备份工具
我用Selenium写了一个人人网相册备份工具,亲测通过. 需要输入你的用户名.密码.相册地址. 代码如下: using System; using System.Collections.Generi ...
- ZENG msgbox仿qq提示
ZENG.msgbox.show("设置成功!", 4, 2000); ZENG.msgbox.show("服务器繁忙,请稍后再试.", 1, 2000); Z ...