码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ1937 [Shoi2004]Mst 最小生成树

时间:2015-05-01 22:25:12      阅读:241      评论:0      收藏:0      [点我收藏+]

标签:

首先由贪心的想法知道,树边只减不加,非树边只加不减,令$w_i$表示i号边原来的边权,$d_i$表示i号边的改变量

对于一条非树边$j$连接着两个点$x$、$y$,则对于$xy$这条路径上的所有树边$i$,都要满足:$w_i - d_i \le w_j + d_j$

移项可得$w_i -w_j \le d_i + d_j$

于是我们发现$d[]$就是KM算法里的顶标了,直接跑最大匹配即可

 

技术分享
  1 /**************************************************************
  2     Problem: 1937
  3     User: rausen
  4     Language: C++
  5     Result: Accepted
  6     Time:700 ms
  7     Memory:4796 kb
  8 ****************************************************************/
  9  
 10 #include <cstdio>
 11 #include <cstring>
 12 #include <algorithm>
 13  
 14 using namespace std;
 15 const int N = 105;
 16 const int M = 1005;
 17 const int inf = 1e9;
 18  
 19 inline int read();
 20  
 21 struct edge {
 22     int next, to, id;
 23     edge(int _n = 0, int _t = 0, int _i = 0) : next(_n), to(_t), id(_i) {}
 24 } e[N << 1];
 25  
 26 struct Edge {
 27     int x, y, v, f;
 28      
 29     inline void get() {
 30         x = read(), y = read(), v = read(), f = 0;
 31     }
 32 } E[M];
 33  
 34 struct tree_node {
 35     int dep, fa[10], e;
 36 } tr[N];
 37  
 38 int n, m;
 39 int first[N], tot;
 40 int mp[M][M];
 41  
 42 namespace KM {
 43     int slack[M], lx[M], ly[M], linky[M];
 44     bool visx[M], visy[M];
 45      
 46     bool find(int x) {
 47         int y, tmp;
 48         for (visx[x] = y = 1; y <= m; ++y) if (!visy[y]) {
 49                 tmp = lx[x] + ly[y] - mp[x][y];
 50                 if (tmp == 0) {
 51                     visy[y] = 1;
 52                     if (linky[y] == -1 || find(linky[y])) {
 53                         linky[y] = x;
 54                         return 1;
 55                     }
 56                 } else
 57                 if (slack[y] > tmp) slack[y] = tmp;
 58             }
 59         return 0;
 60     }
 61  
 62     int work() {
 63         static int i, j, x, d, res;
 64         memset(linky, -1, sizeof(linky));
 65         memset(ly, 0, sizeof(ly));
 66         for (i = 1; i <= m; ++i)
 67             for (j = 1, lx[i] = -inf; j <= m; ++j)
 68                 lx[i] = max(lx[i], mp[i][j]);
 69         for (x = 1; x <= m; ++x) {
 70             for (i = 1; i <= m; ++i)
 71                 slack[i] = inf;
 72             while(1) {
 73                 memset(visx, 0, sizeof(visx));
 74                 memset(visy, 0, sizeof(visy));
 75                 if (find(x)) break;
 76                 d = inf;
 77                 for (i = 1; i <= m; ++i)
 78                     if (!visy[i]) d = min(d, slack[i]);
 79                 for (i = 1; i <= m; ++i)
 80                     if (visx[i]) lx[i] -= d;
 81                 for (i = 1; i <= m; ++i)
 82                     if (visy[i]) ly[i] += d;
 83                     else slack[i] -= d;
 84             }
 85         }
 86         for (res = 0, i = 1; i <= m; ++i)
 87             res += mp[linky[i]][i];
 88         return res;
 89     }
 90 };
 91  
 92 inline void Add_Edges(int x, int y, int id) {
 93     e[++tot] = edge(first[x], y, id), first[x] = tot;
 94     e[++tot] = edge(first[y], x, id), first[y] = tot;
 95 }
 96  
 97 #define y e[x].to
 98 inline void dfs(int p) {
 99     int i, x;
100     tr[p].dep = tr[tr[p].fa[0]].dep + 1;
101     for (i = 1; i <= 6; ++i)
102         tr[p].fa[i] = tr[tr[p].fa[i - 1]].fa[i - 1];
103     for (x = first[p]; x; x = e[x].next)
104         if (y != tr[p].fa[0]) {
105             tr[y].fa[0] = p, tr[y].e = e[x].id;
106             dfs(y);
107         }
108 }
109 #undef y
110  
111 inline int lca(int x, int y) {
112     static int i;
113     if (tr[x].dep < tr[y].dep) swap(x, y);
114     for (i = 6; ~i; --i)
115         if (tr[tr[x].fa[i]].dep >= tr[y].dep) x = tr[x].fa[i];
116     if (x == y) return x;
117     for (i = 6; ~i; --i)
118         if (tr[x].fa[i] != tr[y].fa[i])
119             x = tr[x].fa[i], y = tr[y].fa[i];
120     return tr[x].fa[0];
121 }
122  
123 inline void build(int x, int f, int e, int v) {
124     while (x != f)
125         mp[tr[x].e][e] = max(0, E[tr[x].e].v - v), x = tr[x].fa[0];
126 }
127  
128 int main() {
129     int i, j;
130     int x, y, f;
131     n = read(), m = read();
132     for (i = 1; i <= m; ++i)
133         E[i].get();
134     for (i = 1; i < n; ++i) {
135         x = read(), y = read();
136         for (j = 1; j <= m; ++j)
137             if ((E[j].x == x && E[j].y == y) || (E[j].x == y && E[j].y == x)) {
138                 E[j].f = 1;
139                 Add_Edges(x, y, j);
140                 break;
141             }
142     }
143     dfs(1);
144     for (i = 1; i <= m; ++i)
145         if (!E[i].f) {
146             x = E[i].x, y = E[i].y, f = lca(x, y);
147             build(x, f, i, E[i].v);
148             build(y, f, i, E[i].v);
149         }
150     printf("%d\n", KM::work());
151     return 0;
152 }
153  
154 inline int read() {
155     static int x;
156     static char ch;
157     x = 0, ch = getchar();
158     while (ch < 0 || 9 < ch)
159         ch = getchar();
160     while (0 <= ch && ch <= 9) {
161         x = x * 10 + ch - 0;
162         ch = getchar();
163     }
164     return x;
165 }
View Code

 

BZOJ1937 [Shoi2004]Mst 最小生成树

标签:

原文地址:http://www.cnblogs.com/rausen/p/4471181.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!