• POJ 1741


    LTC男人八题系列,测试数据之强真不是盖的。

    题目大意是在树上找出所有满足长度<=K的简单路径数。首先最朴素的就是就是针对每一个节点dfs一下因为没回路一次是O(N)级别合起来就是O(N2)算法了,铁定超时的节奏。

    看看有没有更快的算法。首先如果选出一个节点,可以知道,要么路径经过这个结点,要么这个路径不经过。

    如果路径经过这个节点,针对简单路径,那么这个路径的两端肯定分别位于这个节点下的两个不同的子树中。

    这时很明确的分治思路就出来了,如果不经过这个节点,那我让它经过这个节点的某个子树的根节点好吧,这就递归了(如图1,在这些圆框框的范围里计算出经过各自粉框框的所有路径,统计下是不是就全了?)。

    但现在还有一个问题,我们怎么才能筛选出不在同一子树情况呢?可以正面做,那就是一个集合的排列组合问题了,好麻烦,有没有更好的办法?

    我们干脆求出经过某节点的所有满足<=K的路径数,不管它是不是简单的路径,然后再找那些在一个子树里的经过根节点的复杂路径,一个子树一个子树的减是不是就ok了?

    如图,看黄圈,其实我们一般认为的路径是红色的简单路径,但通过dfs计算的绿色路径数也有如图且满足长度<=K的,我们要dfs这些子树结点来删除这些绿色路径。让它经过子树的根节点来处理。另外找重心也比较重要,因为分治后的问题基本是独立的,而找到了重心可以让问题规模减少的最快(想想理想情况下的快速排序)。总算法时间复杂度是O(N(logN)2)

      1 #include <cstdio>
      2 #include <cstring>
      3 using namespace std;
      4 
      5 
      6 #define FOR(p,i,s,t) for(__typeof(p) i=s; i<t; ++i)
      7 #define REP(t,i,n)    FOR(t,i,0,n)
      8 
      9 #define ECH(it, A) for (__typeof(A.begin()) it=A.begin(); it != A.end(); ++it)
     10 #define RST(x,y) memset(x, y, sizeof(x))
     11 #define RST0(x)    RST(x,0)
     12 
     13 typedef int Vt, Lt;
     14 const __typeof(Vt) MAXV = 10005;
     15 
     16 #define MAXE    ((MAXV<<1) - 2)
     17 
     18 Vt Vefw[MAXE], Veh[MAXV], eptr = 0;
     19 struct Vedge {
     20     Vt t;
     21     Lt l;
     22     Vedge() {}
     23     Vedge(Vt _t): t(_t), l(1) {}
     24     Vedge(Vt _t, Lt _l): t(_t), l(_l) {}
     25     void attach(Vt s) {
     26         extern Vedge Vs[];
     27         Vs[eptr].t = this->t, Vs[eptr].l = this->l;
     28         Vefw[eptr] = Veh[s]; Veh[s] = ++eptr;
     29     }
     30 };
     31 #define addedge(s,t,l) ({Vedge e(t,l); e.attach(s);})
     32 Vedge Vs[MAXE];
     33 Vt gcoref_tot;
     34 char gc_8[MAXV];
     35 Vt gc_maxk[MAXV], gc_sumn[MAXV];
     36 
     37 int gc_root;
     38 
     39 void gcoref(Vt i)
     40 {
     41     char _gc8;
     42     if (!(_gc8 = gc_8[i])) gc_8[i] = -1;    // 遍历去环
     43     Vt sumn = 1, maxk = 0;
     44     for(Vt e = Veh[i]; e; e = Vefw[e]) {
     45         Vt t = Vs[--e].t;
     46         if (!gc_8[t]) {
     47             gcoref(t);
     48             sumn += gc_sumn[t];
     49             if (maxk < gc_sumn[t])
     50                 maxk = gc_sumn[t];
     51         }
     52     }
     53     gc_8[i] = _gc8;                // gc_8还有其他用途
     54     if (gcoref_tot - sumn > maxk) maxk = gcoref_tot - sumn;
     55     gc_sumn[i] = sumn, gc_maxk[i] = maxk;
     56     if (gc_maxk[gc_root] > maxk) gc_root = i;
     57 }
     58 
     59 inline Vt gcore(Vt root)
     60 {
     61     gc_maxk[gc_root = root] = gcoref_tot;
     62     gcoref(root);
     63     return gc_root;
     64 }
     65 
     66 int K;
     67 #define dist gc_sumn
     68 Vt sorted_dist[MAXV], sorted_tot;
     69 
     70 void upddis(Vt s)
     71 {
     72     char _gc8;
     73     if (!(_gc8 = gc_8[s])) gc_8[s] = -1;    // 遍历去环
     74     for(Vt e = Veh[s]; e; e = Vefw[e]) {
     75         Vt t = Vs[--e].t;
     76         if (!gc_8[t]) {
     77             if ((dist[t] = dist[s] + Vs[e].l) <= K) {
     78                 sorted_dist[sorted_tot++] = dist[t];
     79                 upddis(t);
     80             }
     81         }
     82     }
     83     gc_8[s] = _gc8;
     84 }
     85 
     86 #include <algorithm>
     87 
     88 int calcpairs(Lt walked, Vt s)
     89 {
     90     sorted_dist[0] = dist[s] = walked, sorted_tot = 1;
     91     upddis(s);
     92     sort(sorted_dist, sorted_dist + sorted_tot);
     93 
     94     int pairs = 0;
     95     Vt i, j;
     96 
     97     i = 0, j = sorted_tot - 1;
     98     while(i < j)
     99         if (sorted_dist[i] + sorted_dist[j] <= K)
    100             pairs += j - i++;
    101         else --j;
    102     return pairs;
    103 }
    104 
    105 Vt subtree_ntot[MAXV];
    106 
    107 int solve(Vt s)
    108 {
    109     Vt root = gcore(s);
    110     for(Vt e = Veh[root]; e; e = Vefw[e]) {    // 保护子树的结点数
    111         Vt t = Vs[--e].t;
    112         subtree_ntot[t] = gc_sumn[t];
    113     }
    114     int pairs = calcpairs(0, root);
    115     gc_8[root] = 2;
    116     for(Vt e = Veh[root]; e; e = Vefw[e]) {
    117         Vt t = Vs[--e].t;
    118         if (!gc_8[t]) {
    119             gcoref_tot = subtree_ntot[t];
    120             pairs -= calcpairs(Vs[e].l, t);
    121             pairs += solve(t);
    122         }
    123     }
    124     return pairs;
    125 }
    126 
    127 Vt N;
    128 
    129 int main(void)
    130 {
    131 //    freopen("poj1741.txt", "r", stdin);
    132     while(scanf("%d%d", &N,&K), N && K) {
    133         Vt root = 0;
    134         REP(int, i, N-1) {
    135             Lt l;
    136             Vt s,t;
    137             scanf("%d%d%d", &s, &t, &l); --s, --t;
    138             addedge(s,t,l), addedge(t,s,l);
    139             if (root == t) root = s;
    140         }
    141         gcoref_tot = N;
    142         printf("%d
    ", solve(root));
    143         RST0(gc_8), RST0(Veh), eptr = 0;
    144     }
    145     return 0;
    146 }
    1741 Accepted 1124K 219MS G++ 2968B 2014-05-03 15:26:17
  • 相关阅读:
    Hdu 1257 最少拦截系统
    Hdu 1404 Digital Deletions
    Hdu 1079 Calendar Game
    Hdu 1158 Employment Planning(DP)
    Hdu 1116 Play on Words
    Hdu 1258 Sum It Up
    Hdu 1175 连连看(DFS)
    Hdu 3635 Dragon Balls (并查集)
    Hdu 1829 A Bug's Life
    Hdu 1181 变形课
  • 原文地址:https://www.cnblogs.com/e0e1e/p/poj_1741.html
Copyright © 2020-2023  润新知