【BZOJ2521】 [Shoi2010]最小生成树

Description

Secsa最近对最小生成树问题特别感兴趣。他已经知道如果要去求出一个n个点、m条边的无向图的最小生成树有一个Krustal算法和另一个Prim的算法。另外,他还知道,某一个图可能有多种不同的最小生成树。例如,下面图 3中所示的都是图 2中的无向图的最小生成树:

 

当然啦,这些都不是今天需要你解决的问题。Secsa想知道对于某一条无向图中的边AB,至少需要多少代价可以保证AB边在这个无向图的最小生成树中。为了使得AB边一定在最小生成树中,你可以对这个无向图进行操作,一次单独的操作是指:先选择一条图中的边 P1P2,再把图中除了这条边以外的边,每一条的权值都减少1。如图 4所示就是一次这样的操作:

 

Input

输入文件的第一行有3个正整数n、m、Lab分别表示无向图中的点数、边数、必须要在最小生成树中出现的AB边的标号。
接下来m行依次描述标号为1,2,3…m的无向边,每行描述一条边。每个描述包含3个整数x、y、d,表示这条边连接着标号为x、y的点,且这条边的权值为d。
输入文件保证1<=x,y<=N,x不等于y,且输入数据保证这个无向图一定是一个连通图。

Output

输出文件只有一行,这行只有一个整数,即,使得标号为Lab边一定出现最小生成树中的最少操作次数。

Sample Input

4 6 1
1 2 2
1 3 2
1 4 3
2 3 2
2 4 4
3 4 5

Sample Output

1

HINT

第1个样例就是问题描述中的例子。


1<=n<=500,1<=M<=800,1<=D<10^6

Source

day2

Solution

思路很神的一道题。

首先,其他所有边权值-1可以看做这条边+1。如果选定的边本来就在最小生成树上就不用管它。

如果不在MST上的话,就要考虑想办法让它在MST上。让它在MST上的条件是s,t两个联通块之间一定不存在权值比它更小的边。

对于所有比选定的边边权小的边,让它一定不出现在MST上的代价就是让它的边权变为选定的边权+1。问题就变成了选定一些边使得s和t不连通,且边权总和最小。然后就变成了最小割模型,用网络流来解决。

Code

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 
 5 #define maxn 510
 6 #define maxm 810
 7 #define R register
 8 #define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
 9 #define inf 0x7fffffff
10 int n;
11 struct edge {int a, b, w; } ee[maxm];
12 struct Edge {
13     Edge *next, *rev;
14     int to, cap;
15 } *cur[maxn], *last[maxn], e[maxm << 2], *ecnt = e;
16 inline void link(R int a, R int b, R int w)
17 {
18     *++ecnt = (Edge) {last[a], ecnt + 1, b, w}; last[a] = ecnt;
19     *++ecnt = (Edge) {last[b], ecnt - 1, a, 0}; last[b] = ecnt;
20 }
21 int s, t, dep[maxn], q[maxn], ans;
22 inline bool bfs()
23 {
24     R int head = 0, tail = 1;
25     memset(dep, -1, (n + 1) << 2);
26     dep[q[1] = t] = 0;
27     while (head < tail)
28     {
29         R int now = q[++head];
30         for (R Edge *iter = last[now]; iter; iter = iter -> next)
31             if (iter -> rev -> cap && dep[iter -> to] == -1)
32                 dep[q[++tail] = iter -> to] = dep[now] + 1;
33     }
34     return dep[s] != -1;
35 }
36 int dfs(R int x, R int f)
37 {
38     if (x == t) return f;
39     R int used = 0;
40     for (R Edge* &iter = cur[x]; iter; iter = iter -> next)
41         if (iter -> cap && dep[iter -> to] + 1 == dep[x])
42         {
43             R int v = dfs(iter -> to, dmin(f - used, iter -> cap));
44             iter -> cap -= v;
45             iter -> rev -> cap += v;
46             used += v;
47             if (used == f) return f;
48         }
49     return used;
50 }
51 inline void dinic()
52 {
53     while (bfs())
54     {
55         memcpy(cur, last, sizeof cur);
56         ans += dfs(s, inf);
57     }
58 }
59 int main()
60 {
61     R int m, lab; scanf("%d%d%d", &n, &m, &lab);
62     for (R int i = 1; i <= m; ++i) scanf("%d%d%d", &ee[i].a, &ee[i].b, &ee[i].w);
63     for (R int i = 1; i <= m; ++i)
64         if (ee[i].w <= ee[lab].w && i != lab)
65         {
66             link(ee[i].a, ee[i].b, ee[lab].w - ee[i].w + 1);
67             link(ee[i].b, ee[i].a, ee[lab].w - ee[i].w + 1);
68         }
69     s = ee[lab].a; t = ee[lab].b;
70     dinic();
71     printf("%d
", ans);
72     return 0;
73 }
原文地址:https://www.cnblogs.com/cocottt/p/6781823.html