206. Roads

time limit per test: 0.5 sec.
memory limit per test: 65536 KB
input: standard
output: standard

The kingdom of Farland has N cities connected by M roads. Some roads are paved with stones, others are just country roads. Since paving the road is quite expensive, the roads to be paved were chosen in such a way that for any two cities there is exactly one way to get from one city to another passing only the stoned roads.

The kingdom has a very strong bureaucracy so each road has its own ordinal number ranging from 1 to M: the stoned roads have numbers from 1 to N-1 and other roads have numbers from N to M. Each road requires some money for support, i-th road requires ci coins per year to keep it intact. Recently the king has decided to save some money and keep financing only some roads. Since he wants his people to be able to get from any city to any other, he decided to keep supporting some roads in such a way, that there is still a path between any two cities.

It might seem to you that keeping the stoned roads would be the good idea, however the king did not think so. Since he did not like to travel, he did not know the difference between traveling by a stoned road and travelling by a muddy road. Thus he ordered you to bring him the costs of maintaining the roads so that he could order his wizard to choose the roads to keep in such a way that the total cost of maintaining them would be minimal.

Being the minister of communications of Farland, you want to help your people to keep the stoned roads. To do this you want to fake the costs of maintaining the roads in your report to the king. That is, you want to provide for each road the fake cost of its maintaining di in such a way, that stoned roads form the set of roads the king would keep. However, to lower the chance of being caught, you want the value of sum(i = 1..M, |ci-di|) to be as small as possible.

You know that the king's wizard is not a complete fool, so if there is the way to choose the minimal set of roads to be the set of the stoned roads, he would do it, so ties are allowed.

Input

The first line of the input file contains N and M (2 ≤ N ≤ 60, N-1 ≤ M ≤ 400). Next M lines contain three integer numbers ai, bi and ci each — the numbers of the cities the road connects (1 ≤ ai ≤ N, 1 ≤ bi ≤ N, ai ≠ bi) and the cost of maintaining it (1 ≤ ci ≤ 10 000).

Output

Output M lines — for each road output di that should be reported to be its maintainance cost so that he king would choose first N-1 roads to be the roads to keep and the specified sum is minimal possible.

Sample test(s)

Input

4 5
4 1 7
2 1 5
3 4 4
4 2 5
1 3 1

Output

4
5
4
5
4

题意

给你m条带权边,保证前n-1条边成为一颗树,要求改变边的权值,使得最小生成树为前n-1条边,求最小改变量方案。


很棒的一道非常经典的匹配模型的题!早在1999年,网络流大牛Ahuja(《Network Flows: Theory, Algorithms and Applications》的作者)就对此进行了研究,并提出了\(O(n^2\log n)\)的优秀算法(但是由于没有使用Tex导致排版很DT。。不过好在不影响阅读)。链接在

该问题被称为 Inverse Spanning Tree Problem

摘录ABSTRACT如下:

In this paper, we consider the inverse spanning tree problem. Given an undirected graph G0 = (N0, A0)with n nodes, m arcs, an arc cost vector c, and a spanning tree T0, the inverse spanning tree problem is toperturb the arc cost vector c to a vector d so that T0 is a minimum spanning tree with respect to the costvector d and the cost of perturbation given by |d – c| = |d c |ij ij (i, j) A − is minimum. We show that the dual of the inverse spanning tree problem is a bipartite node weighted matching problem on a specially structured graph (which we call the path graph) that contains m nodes and as many as (m-n+1)(n-1) = O(nm) arcs. We first transform the bipartite node weighted matching problem into a specially structured minimum cost flow problem and use its special structure to develop an O(n3) algorithm. We next use its special structure more effectively and develop an O(n2 log n) time algorithm. This improves the previous O(n3) time algorithm due to Sokkalingam, Ahuja and Orlin [1999].

作者对该问题建立网络流模型,得到\(O(n^3)\)的解决方案,然后又通过use its special structure more effectively得到\(O(n^2\log n)\)的计算方式,而非动态树优化。。。Tarjan逆天。。常数大到爆。原话:

The algorithm given in Figure 1 can also be implemented in \(O(n^2 \log n)\) time using the dynamic tree data structure due to Sleator and Tarjan [1983]. However,the dynamic tree data structure has large computational overhead and is difficult to implement. In the next section, we describe another \(O(n^2 \log n)\) algorithm that is simpler and is easier to implement. In fact, our improved implementation of the node weighted matching algorithm is the same as the one described above, except that it is carried out on a transformed network.

如下为\(O(n^3)\)的做法,使用加slack优化的KM算法。

首先注意到:如果最开始的边是最小生成树上的边,那么就要求在后面的边在加入到树后形成的环内为环上最大权边,否则就可以把要求的边更新掉。不妨设Akane[i]为边i的边权值,Ranma[i]为边i需要改变的值,那么对于加入的第n~m条内的边k,要求对环内每条Akane值大于加入边值的边j都有:Akane[k] <= Akane[j],Akane[j]-Ranma[j]<= Akane[k]+Ranma[k],移项得:Akane[j]-Akane[k]<=Ranma[j] +Ranma[k],左边为常量,右边是我们要均衡分配的权值,而这正是KM匹配算法的标准形式,如是我们可以建立模型,从而解决此问题。

至于\(O(n^2\log n)\)的做法,sbit略感兴趣,但最近有点忙(改noi(p)模拟题。。),留个坑,如果您对此也有兴趣,欢迎和sbit讨论。。(可以增长见识 出题时卡时限 啊什么的。。。)

#include <bits/stdc++.h>
#define rep(_i, _j) for(int _i = 1; _i <= _j; ++_i)
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef double DB;
using namespace std;
const int maxn = 60 + 5;
const int maxd = 400 + 20;
struct Edge {
int edge, head[maxn], cost[maxn * 2], to[maxn * 2], next[maxn * 2];
Edge() {
edge = 0;
memset(head, -1, sizeof head);
}
void addedge(int u, int v, int c) {
next[edge] = head[u];
cost[edge] = c;
to[edge] = v;
head[u] = edge++;
}
} E;
int n, m;
int g[maxd][maxd], c[maxd]; bool calc(int p, int fa, int goal, int id, int cost) {
if(p == goal) return true;
for(int i = E.head[p]; i != -1; i = E.next[i]) {
if(E.to[i] != fa && calc(E.to[i], p, goal, id, cost)) {
g[i >> 1][id] = max(g[i >> 1][id], E.cost[i] - cost);
return true;
}
}
return false;
}
bool visx[maxd], visy[maxd];
int link[maxd], lx[maxd], ly[maxd], N, slack; bool dfs(int u) {
visx[u] = true;
for(int i = 0, tmp; i < N; ++i) if(!visy[i]) {
tmp = lx[u] + ly[i] - g[u][i];
if(tmp == 0) {
visy[i] = true;
if(link[i] == -1 || dfs(link[i])) {
link[i] = u;
return true;
}
} else {
slack = min(slack, tmp);
}
}
return false;
} int main() {
#ifndef ONLINE_JUDGE
freopen("206.in", "r", stdin); freopen("206.out", "w", stdout);
#endif
scanf("%d%d", &n, &m);
--n, m -= n;
for(int i = 0, a, b, t; i < n; ++i) {
scanf("%d%d%d", &a, &b, &t);
E.addedge(a, b, t), E.addedge(b, a, t);
}
memset(g, 0, sizeof g);
for(int i = 0, a, b; i < m; ++i) {
scanf("%d%d%d", &a, &b, &c[i]);
calc(a, -1, b, i, c[i]);
}
N = max(n, m);
memset(link, -1, sizeof link);
for(int i = 0; i < N; ++i) {
for(int j = 0; j < N; ++j) {
lx[i] = max(lx[i], g[i][j]);
}
}
for(int i = 0; i < N; ++i) {
for(;;) {
slack= INF;
memset(visx, false, sizeof(visx[0]) * N);
memset(visy, false, sizeof(visy[0]) * N);
if(dfs(i)) break;
for(int j = 0; j < N; ++j) {
if(visx[j]) lx[j] -= slack;
if(visy[j]) ly[j] += slack;
}
}
}
for(int i = 0; i < n; ++i) {
printf("%d\n", E.cost[i << 1] - lx[i]);
}
for(int i = 0; i < m; ++i) {
printf("%d\n", ly[i] + c[i]);
} return 0;
}

SGU 206. Roads的更多相关文章

  1. [转] POJ图论入门

    最短路问题此类问题类型不多,变形较少 POJ 2449 Remmarguts' Date(中等)http://acm.pku.edu.cn/JudgeOnline/problem?id=2449题意: ...

  2. 图论常用算法之一 POJ图论题集【转载】

    POJ图论分类[转] 一个很不错的图论分类,非常感谢原版的作者!!!在这里分享给大家,爱好图论的ACMer不寂寞了... (很抱歉没有找到此题集整理的原创作者,感谢知情的朋友给个原创链接) POJ:h ...

  3. SGU 185 Two shortest

    Two shortest Time Limit: 500ms Memory Limit: 4096KB This problem will be judged on SGU. Original ID: ...

  4. PIC10F200/202/204/206/220/222/320/322芯片解密程序复制多少钱?

    PIC10F200/202/204/206/220/222/320/322芯片解密程序复制多少钱? PIC10F单片机芯片解密型号: PIC10F200解密 | PIC10F202解密 | PIC10 ...

  5. poj 1251 Jungle Roads (最小生成树)

    poj   1251  Jungle Roads  (最小生成树) Link: http://poj.org/problem?id=1251 Jungle Roads Time Limit: 1000 ...

  6. Jungle Roads[HDU1301]

    Jungle Roads Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  7. POJ1947 Rebuilding Roads[树形背包]

    Rebuilding Roads Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 11495   Accepted: 5276 ...

  8. Constructing Roads——F

    F. Constructing Roads There are N villages, which are numbered from 1 to N, and you should build som ...

  9. leetcode 206

    206. Reverse Linked List Reverse a singly linked list. 翻转一个单链表. 代码如下: /** * Definition for singly-li ...

随机推荐

  1. 网络编程----socket介绍、基于tcp协议的套接字实现、基于udp协议的套接字实现

    一.客户端/服务器架构(C/S架构)                                                即C/S架构,包括: 1.硬件C/S架构(打印机) 2.软件C/S架 ...

  2. C++之正则表达式20171121

    准确来说,不论在C++或C中,只要在Linux系统中都可以使用本文讲诉的正则表达式使用方式. 一.Linux中正则表达式的使用步骤: 编译正则表达式 regcomp() 匹配正则表达式 regexec ...

  3. MDK5.13新建工程步骤

    http://www.stmcu.org/module/forum/thread-600249-1-1.html 本人也是接触stm32没多久,之前用的MDK是5.1,现在用的是5.13,MDK5.0 ...

  4. horizon源码分析(二)

    源码版本:H版 一.简要回顾 对于请求: 地址:/dashboard/admin/instances/ 方式:POST 参数: instances_filter_q: action:instances ...

  5. 使用 JSONDoc 记录 Spring Boot RESTful API

    这个博文可以分为两部分:第一部分我将编写一个Spring Boot RESTful API,第二部分将介绍如何使用JSONDoc来记录创建的API.做这两个部分最多需要15分钟,因为使用Spring ...

  6. HDU 1211 EXGCD

    EXGCD的模板水题 RSA算法给你两个大素数p,q定义n=pq,F(n)=(p-1)(q-1) 找一个数e 使得(e⊥F(n)) 实际题目会给你e,p,q计算d,$de \mod F(n) = 1$ ...

  7. HDU 2157 How many ways?? 临接矩阵+快速幂

    Problem Description 春天到了, HDU校园里开满了花, 姹紫嫣红, 非常美丽. 葱头是个爱花的人, 看着校花校草竞相开放, 漫步校园, 心情也变得舒畅. 为了多看看这迷人的校园, ...

  8. 关于拉格朗日乘子法与KKT条件

    关于拉格朗日乘子法与KKT条件 关于拉格朗日乘子法与KKT条件   目录 拉格朗日乘子法的数学基础 共轭函数 拉格朗日函数 拉格朗日对偶函数 目标函数最优值的下界 拉格朗日对偶函数与共轭函数的联系 拉 ...

  9. 给你灵感!21个精美的 iOS APP 网站设计欣赏

    iOS 吹起了轰轰烈烈的扁平化设计风格,而做为承载 App 宣传重任的网页,整体设计风格的变迁如何?是否也如iOS的设计风格改革一样彻底的翻转?还是如往常一直深耕成熟的设计风格? Spendee Fo ...

  10. 那些让 Web 开发者们深感意外的事情

    作为 Web 开发者,对自己的行业前景,人人都有自己的看法,然而,任何行业都有出人意料的地方.著名的 Web 开发设计博客 Nope.com 曾向他们的读者做了一个调查,请他们列举 Web 开发领域那 ...