[关闭]
@wsndy-xx 2018-05-09T16:57:46.000000Z 字数 2731 阅读 938

点分治 算法学习

算法学习


前言

之前貌似也接触过,不过,早忘干净了


点分治基本

顾名思义,点分治就是对树上的点分治,从而进行一些操作。将点拆开,实则将树拆分成许多子树进行处理,并不断进行。


点分治选择

考虑讲一个点进行分治,首先选点(这不是废话吗)。那么如何选点呢?
对比:如果树是一条链,选择链端和链心时间复杂度是明显不同的,前者时间复杂度为 O(n), 而后者为 O(logn).
不难发现,选择的点的子树越大,效率越低,那我们怎么选呢??
当然是树的重心啦
树的重心定义
树的重心也叫树的质心。对于一棵树n个节点的无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点树最小。换句话说,删除这个点后最大连通块(一定是树)的结点数最小。(from 百度百科)
伪代码

  1. size[] 节点的子树大小
  2. maxson[] 节点的最大子树的大小
  3. Size 这棵树(当前处理的子树)的大小
  4. Max 最大子树值
  5. Root 重心,以重心为根
  6. Getroot(u, fa){
  7. size[u] = 1, maxson[u] = 0;
  8. for(所有与 u 相连的点v) {
  9. if(未被访问 && v != fa) Getroot(v, u);
  10. size[u] += size[v];
  11. maxson[u] = max(maxson[u], size[v]);
  12. }
  13. maxson[u] = max(maxson[u], Size - size[u]);
  14. if(maxson[u] < Max) {Root = u, Max = maxson[u];}
  15. }

点分治实现

看一道非常非常经典的例题吧
poj1741

题意

给一颗 个节点的树,每条边上有一个距离 。定义 的最小距离。给定 值,求有多少点对 使 的距离小于等于
可以这样考虑,先假定一个根 Root, 接下来求出所有经过该点的路径中长度 <= k 的路径个数
那怎么求呢??
对于一条树路径 只有经过或不经过一个点的情况,我们可以用总情况 - 所有不经过的情况就可以求出所有经过的情况啦

  1. void Getans(int u) {
  2. Answer += Calc(u, 0);
  3. vis[u] = 1;
  4. for(int i = head[u]; ~ i; i = G[i].nxt) {
  5. int v = G[i].v;
  6. if(!vis[v]) {
  7. Answer -= Calc(v, G[i].w);
  8. Size = size[v];
  9. Max = oo;
  10. Getroot(v, 0);
  11. Getans(Root);
  12. }
  13. }
  14. return ;
  15. }

line 2 求出的是以 为根时的所有情况
line 7 减去了所有不经过 Root 的路径条数
然后递归处理,重新选 处理 的子节点

下面是一个计算函数
返回 的子树中所有点到 的距离 之后
任意两点之间距离 的点对个数
这里的 处理是为了减去重复答案时方便处理
显然 上一个函数 line 2 时

  1. int Calc(int u, int len) {
  2. tot = 0;
  3. for(int i = 1; i <= n; i ++) dis[i] = 0;
  4. Getdis(u, 0, len);
  5. std:: sort(dis + 1, dis + tot + 1);
  6. int L = 1, R = tot, ret(0);
  7. while(L <= R) {
  8. if(dis[L] + dis[R] <= k) ret += (R - L), L ++;
  9. else R --;
  10. }
  11. return ret;
  12. }

该题完整代码

  1. #include <bits/stdc++.h>
  2. const int N = 1e4 + 10;
  3. const int oo = 1e9;
  4. struct Node {int v, w, nxt;} G[N << 1];
  5. int n, k, now = 1, head[N];
  6. int size[N], maxson[N], dis[N];
  7. bool vis[N];
  8. int Max, Root, tot, Size;
  9. int Answer;
  10. #define gc getchar()
  11. inline int read() {
  12. int x = 0; char c = gc;
  13. while(c < '0' || c > '9') c = gc;
  14. while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
  15. return x;
  16. }
  17. inline void Add(int u, int v, int w) {G[now].v = v; G[now].w = w; G[now].nxt = head[u]; head[u] = now ++;}
  18. void Getroot(int u, int fa) {
  19. size[u] = 1;
  20. maxson[u] = 0;
  21. for(int i = head[u]; ~ i; i = G[i].nxt) {
  22. int v = G[i].v;
  23. if(!vis[v] && v != fa) {
  24. Getroot(v, u);
  25. size[u] += size[v];
  26. maxson[u] = std:: max(maxson[u], size[v]);
  27. }
  28. }
  29. maxson[u] = std:: max(maxson[u], Size - size[u]);
  30. if(maxson[u] < Max) {Max = maxson[u]; Root = u;}
  31. }
  32. void Getdis(int u, int fa, int len) {
  33. dis[++ tot] = len;
  34. for(int i = head[u]; ~ i; i = G[i].nxt) {
  35. int v = G[i].v;
  36. if(!vis[v] && v != fa) Getdis(v, u, len + G[i].w);
  37. }
  38. }
  39. int Calc(int u, int len) {
  40. tot = 0;
  41. for(int i = 1; i <= n; i ++) dis[i] = 0;
  42. Getdis(u, 0, len);
  43. std:: sort(dis + 1, dis + tot + 1);
  44. int L = 1, R = tot, ret(0);
  45. while(L <= R) {
  46. if(dis[L] + dis[R] <= k) ret += (R - L), L ++;
  47. else R --;
  48. }
  49. return ret;
  50. }
  51. void Getans(int u) {
  52. Answer += Calc(u, 0);
  53. vis[u] = 1;
  54. for(int i = head[u]; ~ i; i = G[i].nxt) {
  55. int v = G[i].v;
  56. if(!vis[v]) {
  57. Answer -= Calc(v, G[i].w);
  58. Size = size[v];
  59. Max = oo;
  60. Getroot(v, 0);
  61. Getans(Root);
  62. }
  63. }
  64. return ;
  65. }
  66. int main() {
  67. while(1) {
  68. n = read(), k = read();
  69. if((! n) && (! k)) break;
  70. now = 1;
  71. for(int i = 1; i <= n; ++ i) head[i] = -1, vis[i] = 0;
  72. for(int i = 1; i < n; ++ i) {
  73. int u = read(), v = read(), w = read();
  74. Add(u, v, w), Add(v, u, w);
  75. }
  76. Answer = 0;
  77. Max = oo;
  78. Size = n;
  79. Getroot(1, 0);
  80. Getans(Root);
  81. std:: cout << Answer << "\n";
  82. }
  83. return 0;
  84. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注