zoukankan      html  css  js  c++  java
  • 洛谷P3296 刺客信条

    题意

    给你一棵树,有两组01权值a[]和b[]。n <= 700

    你要构造一个自己到自己的映射,使得整棵树的形态不变,且映射后的a[]和映射之前的b[]中不同元素尽量少。

    解:

    发现这个整棵树形态不变......我们可能要用到树hash。

    有个结论就是两棵树同构,当且仅当以它们重心为根的时候hash值相同。有两个重心就新建一个虚重心。

    于是我们把重心搞出来当根,考虑映射之后的树,如果a映射到了b,那么a和b一定深度相同且hash值相同。

    于是我们就按照深度分层,每层枚举点对,用f[a][b]来表示把点a映射到点b,子树内最少的不同元素。

    于是如何求f[a][b]?发现我们要给a和b的若干个子节点进行匹配,要求权值最小。二分图匹配即可。我采用费用流实现。

    复杂度:O(n³ + n * 网络流),这个复杂度是我猜的...

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 710, MO = 998244353, INF = 0x3f3f3f3f;
      4 
      5 struct Edge {
      6     int nex, v;
      7     bool del;
      8 }edge[N << 1]; int tp = 1;
      9 
     10 int f[N][N], n, e[N], siz[N], val[N], h[N], aim[N], p[1000010], top, small, root, root2, in_e[N], lm, in[N], d[N];
     11 bool vis[1000010];
     12 std::vector<int> v[N];
     13 
     14 inline void getp(int n) {
     15     for(int i = 2; i <= n; i++) {
     16         if(!vis[i]) {
     17             p[++top] = i;
     18         }
     19         for(int j = 1; j <= top && i * p[j] <= n; j++) {
     20             vis[i * p[j]] = 1;
     21             if(i % p[j] == 0) {
     22                 break;
     23             }
     24         }
     25     }
     26     return;
     27 }
     28 
     29 inline void add(int x, int y) {
     30     tp++;
     31     edge[tp].v = y;
     32     edge[tp].del = 0;
     33     edge[tp].nex = e[x];
     34     e[x] = tp;
     35     return;
     36 }
     37 
     38 void getroot(int x, int f) {
     39     int large = 0;
     40     siz[x] = 1;
     41     for(int i = e[x]; i; i = edge[i].nex) {
     42         int y = edge[i].v;
     43         if(y == f) {
     44             continue;
     45         }
     46         in_e[y] = i;
     47         getroot(y, x);
     48         siz[x] += siz[y];
     49         large = std::max(large, siz[y]);
     50     }
     51     large = std::max(large, n - siz[x]);
     52     if(large < small) {
     53         root = x;
     54         root2 = 0;
     55         small = large;
     56     }
     57     else if(large == small) {
     58         root2 = x;
     59     }
     60     return;
     61 }
     62 
     63 void DFS_1(int x, int f) {
     64     d[x] = d[f] + 1;
     65     v[d[x]].push_back(x);
     66     lm = std::max(lm, d[x]);
     67     h[x] = 1;
     68     for(int i = e[x]; i; i = edge[i].nex) {
     69         int y = edge[i].v;
     70         if(y == f || edge[i].del) {
     71             continue;
     72         }
     73         DFS_1(y, x);
     74         siz[x] += siz[y];
     75         h[x] = (h[x] + 1ll * h[y] * p[siz[y]] % MO) % MO;
     76     }
     77     return;
     78 }
     79 
     80 namespace fl {
     81 
     82     struct Edge {
     83         int nex, v, c, len;
     84         Edge(int N = 0, int V = 0, int C = 0, int L = 0) {
     85             nex = N;
     86             v = V;
     87             c = C;
     88             len = L;
     89         }
     90     }edge[2000010]; int tp = 1;
     91 
     92     int e[N], d[N], vis[N], Time, pre[N], flow[N], n, tot;
     93     std::queue<int> Q;
     94 
     95     inline void add(int x, int y, int z, int w) {
     96         //printf("addedge : x = %d y = %d z = %d w = %d 
    ", x, y, z, w);
     97         edge[++tp] = Edge(e[x], y, z, w);
     98         e[x] = tp;
     99         edge[++tp] = Edge(e[y], x, 0, -w);
    100         e[y] = tp;
    101         return;
    102     }
    103 
    104     inline bool SPFA(int s, int t) {
    105         vis[s] = Time;
    106         memset(d + 1, 0x3f, tot * sizeof(int));
    107         flow[s] = INF;
    108         d[s] = 0;
    109         Q.push(s);
    110         while(Q.size()) {
    111             int x = Q.front();
    112             Q.pop();
    113             vis[x] = 0;
    114             for(int i = e[x]; i; i = edge[i].nex) {
    115                 int y = edge[i].v;
    116                 if(d[y] > d[x] + edge[i].len && edge[i].c) {
    117                     d[y] = d[x] + edge[i].len;
    118                     flow[y] = std::min(edge[i].c, flow[x]);
    119                     pre[y] = i;
    120                     if(vis[y] != Time) {
    121                         vis[y] = Time;
    122                         Q.push(y);
    123                     }
    124                 }
    125             }
    126         }
    127         return d[t] < INF;
    128     }
    129 
    130     inline void update(int s, int t) {
    131 
    132         int f = flow[t];
    133         while(s != t) {
    134             int i = pre[t];
    135             edge[i].c -= f;
    136             edge[i ^ 1].c += f;
    137             t = edge[i ^ 1].v;
    138         }
    139         return;
    140     }
    141 
    142     inline int solve(int x, int y) {
    143 
    144         int ans = 0, cost = 0;
    145         n = in[x] - (x != root);
    146         int s = 2 * n + 1, t = tot = s + 1;
    147         //printf("solve : x = %d  y = %d  n = %d 
    ", x, y, n);
    148         memset(e + 1, 0, tot * sizeof(int));
    149         tp = 1;
    150 
    151         for(int i = ::e[x], cnt1 = 1; i; i = ::edge[i].nex, ++cnt1) {
    152             int u = ::edge[i].v;
    153             //printf("u = %d 
    ", u);
    154             if(::d[u] < ::d[x] || ::edge[i].del) {
    155                 --cnt1;
    156                 continue;
    157             }
    158             add(s, cnt1, 1, 0);
    159             add(cnt1 + n, t, 1, 0);
    160             for(int j = ::e[y], cnt2 = 1; j; j = ::edge[j].nex, ++cnt2) {
    161                 int v = ::edge[j].v;
    162                 //printf("    v = %d 
    ", v);
    163                 if(::d[v] < ::d[y] || ::edge[j].del) {
    164                     --cnt2;
    165                     continue;
    166                 }
    167                 /// u v
    168                 if(f[u][v] > -INF) {
    169                     add(cnt1, n + cnt2, 1, f[u][v]);
    170                 }
    171 
    172             }
    173         }
    174 
    175         ++Time;
    176         while(SPFA(s, t)) {
    177             //printf("inside --------------------- 
    ");
    178             ans += flow[t];
    179             cost += flow[t] * d[t];
    180             update(s, t);
    181             ++Time;
    182         }
    183 
    184         //printf("ans = %d cost = %d 
    ", ans, cost);
    185         if(ans != n) {
    186             return -INF;
    187         }
    188         else {
    189             return cost + (val[x] != aim[y]);
    190         }
    191     }
    192 }
    193 
    194 int main() {
    195 
    196     scanf("%d", &n);
    197     for(int i = 1, x, y; i < n; i++) {
    198         scanf("%d%d", &x, &y);
    199         add(x, y);
    200         add(y, x);
    201         in[x]++;
    202         in[y]++;
    203     }
    204     for(int i = 1; i <= n; i++) {
    205         scanf("%d", &val[i]);
    206     }
    207     for(int i = 1; i <= n; i++) {
    208         scanf("%d", &aim[i]);
    209     }
    210     root = root2 = 0;
    211     small = N;
    212     getroot(1, 0);
    213     //printf("root 1 = %d  root 2 = %d 
    ", root, root2);
    214 
    215     if(root2) {
    216         ++n;
    217         int i;
    218         if(edge[in_e[root] ^ 1].v == root2) {
    219             i = in_e[root];
    220         }
    221         else {
    222             i = in_e[root2];
    223         }
    224         edge[i].del = edge[i ^ 1].del = 1;
    225         add(n, root);
    226         add(n, root2);
    227         root = n;
    228         in[n] = 2;
    229     }
    230     ///
    231 
    232     //printf("root = %d 
    ", root);
    233 
    234     DFS_1(root, 0);
    235 
    236     for(int d = lm; d >= 1; d--) {
    237         int len = v[d].size();
    238         for(int i = 0; i < len; i++) {
    239             int x = v[d][i];
    240             for(int j = 0; j < len; j++) {
    241                 int y = v[d][j];
    242                 if(in[x] != in[y] || h[x] != h[y]) {
    243                     f[x][y] = -INF;
    244                     //printf("1 : ");
    245                 }
    246                 else {
    247                     //f[x][y] = KM::solve(x, y);
    248                     f[x][y] = fl::solve(x, y);
    249                     //printf("2 : ");
    250                 }
    251                 //printf("f %d %d = %d 
    ", x, y, f[x][y]);
    252             }
    253         }
    254     }
    255 
    256     printf("%d
    ", f[root][root]);
    257     return 0;
    258 }
    AC代码
  • 相关阅读:
    2019.8.30 玉米田
    2019暑假集训 最短路计数
    2019暑假集训 旅行计划
    2019暑假集训 文件压缩
    0033-数字和星期转换
    0032-分数等级转换
    0031-闰年判断
    0030-购买衣服
    0029-求最小的数
    0028-判断奇偶
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10819455.html
Copyright © 2011-2022 走看看