• BZOJ1937 [Shoi2004]Mst 最小生成树


    首先由贪心的想法知道,树边只减不加,非树边只加不减,令$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
    ", 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
    By Xs酱~ 转载请说明 博客地址:http://www.cnblogs.com/rausen
  • 相关阅读:
    Keras & Theano 输出中间层结果
    keras & tensorflow 列出可用GPU 和 切换CPU & GPU
    Visualizing CNN Layer in Keras
    [python]使用django快速生成自己的博客小站,含详细部署方法
    [JetBrains注册] 利用教育邮箱注册JetBrains产品(pycharm、idea等)的方法
    【python】pycharm常用配置快速入门。
    一道笔试题来理顺Java中的值传递和引用传递
    集群扩容的常规解决:一致性hash算法
    [面经]春季跳槽面筋总结 [2018年3月17]
    TestNG的简单使用
  • 原文地址:https://www.cnblogs.com/rausen/p/4471181.html
Copyright © 2020-2023  润新知