首先由贪心的想法知道,树边只减不加,非树边只加不减,令$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算法里的顶标了,直接跑最大匹配即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
By Xs酱~ 转载请说明
博客地址:http://www.cnblogs.com/rausen