挑战程序竞赛系列(59):4.6树上的分治法(2)
来源:互联网 发布:生活中的帅哥知乎 编辑:程序博客网 时间:2024/05/29 14:48
挑战程序竞赛系列(59):4.6树上的分治法(2)
传送门:POJ 1741: Tree
思路:
首先还是求树的重心,这样可以把问题划分成多个子问题(树是天然的递归),之所以找重心考虑分治的效率问题,每次问题规模减少n/2,所以最终的时间复杂度为
分为三种情况:
- 顶点 v, w属于同一子树的顶点对(v, w)
- 顶点 v,w 属于不同子树的顶点对(v, w)
- 顶点s和其他顶点v组成的顶点对(v, w)
代码如下:
import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.util.Arrays;import java.util.StringTokenizer;public class Main{ String INPUT = "./data/judge/201709/P1741.txt"; public static void main(String[] args) throws IOException { new Main().run(); } static final int MAX_N = 10000 + 16; static final int INF = 0x3f3f3f3f; class Edge{ int to; int cost; int next; Edge(int to, int cost, int next){ this.to = to; this.cost = cost; this.next = next; } @Override public String toString() { return to + " " + cost + " " + next; } } Edge[] edges = new Edge[MAX_N << 1]; int N, K, tot, cenv, minv, ans, point; int[] head, son; int[] dis; boolean[] visited; void init() { head = new int[MAX_N]; son = new int[MAX_N]; dis = new int[MAX_N]; visited = new boolean[MAX_N]; cenv = point = tot = 0; minv = INF; Arrays.fill(head, -1); } void add(int from, int to, int cost) { edges[tot] = new Edge(to, cost, head[from]); head[from] = tot++; } void dfs(int u, int fa) { son[u] = 0; int maxv = 0; for (int i = head[u]; i != -1; i = edges[i].next) { int v = edges[i].to; if (v == fa || visited[v]) continue; dfs(v, u); son[u] += son[v] + 1; maxv = Math.max(maxv, son[v] + 1); } maxv = Math.max(maxv, point - 1 - son[u]); if (maxv < minv) { minv = maxv; cenv = u; } } void getDis(int u, int fa, int dist) { dis[tot++] = dist; for (int i = head[u]; i != -1; i = edges[i].next) { int v = edges[i].to; if (v == fa || visited[v]) continue; getDis(v, u, dist + edges[i].cost); } } int count(int u, int d) { tot = 0; getDis(u, -1, d); Arrays.sort(dis, 0, tot); int l = 0, r = tot - 1, res = 0; while (l < r) { if (dis[l] + dis[r] <= K) { res += r - l; l ++; } else r --; } return res; } void solve(int u) { minv = INF; point = point != 0 ? son[u] + 1 : N; dfs(u, -1); int root = cenv; visited[root] = true; ans += count(root, 0); for (int i = head[root]; i != -1; i = edges[i].next) { int v = edges[i].to; if (visited[v]) continue; ans -= count(v, edges[i].cost); solve(v); } } void read() { while (true) { N = ni(); K = ni(); if (N == 0 && K == 0) break; init(); for (int i = 1; i < N; ++i) { int from = ni(); int to = ni(); int cost = ni(); add(from, to, cost); add(to, from, cost); } ans = 0; solve(1); out.println(ans); } } FastScanner in; PrintWriter out; void run() throws IOException { boolean oj; try { oj = ! System.getProperty("user.dir").equals("F:\\java_workspace\\leetcode"); } catch (Exception e) { oj = System.getProperty("ONLINE_JUDGE") != null; } InputStream is = oj ? System.in : new FileInputStream(new File(INPUT)); in = new FastScanner(is); out = new PrintWriter(System.out); long s = System.currentTimeMillis(); read(); out.flush(); if (!oj){ System.out.println("[" + (System.currentTimeMillis() - s) + "ms]"); } } public boolean more(){ return in.hasNext(); } public int ni(){ return in.nextInt(); } public long nl(){ return in.nextLong(); } public double nd(){ return in.nextDouble(); } public String ns(){ return in.nextString(); } public char nc(){ return in.nextChar(); } class FastScanner { BufferedReader br; StringTokenizer st; boolean hasNext; public FastScanner(InputStream is) throws IOException { br = new BufferedReader(new InputStreamReader(is)); hasNext = true; } public String nextToken() { while (st == null || !st.hasMoreTokens()) { try { st = new StringTokenizer(br.readLine()); } catch (Exception e) { hasNext = false; return "##"; } } return st.nextToken(); } String next = null; public boolean hasNext(){ next = nextToken(); return hasNext; } public int nextInt() { if (next == null){ hasNext(); } String more = next; next = null; return Integer.parseInt(more); } public long nextLong() { if (next == null){ hasNext(); } String more = next; next = null; return Long.parseLong(more); } public double nextDouble() { if (next == null){ hasNext(); } String more = next; next = null; return Double.parseDouble(more); } public String nextString(){ if (next == null){ hasNext(); } String more = next; next = null; return more; } public char nextChar(){ if (next == null){ hasNext(); } String more = next; next = null; return more.charAt(0); } } static class ArrayUtils { public static void fill(int[][] f, int value) { for (int i = 0; i < f.length; ++i) { Arrays.fill(f[i], value); } } public static void fill(int[][][] f, int value) { for (int i = 0; i < f.length; ++i) { fill(f[i], value); } } public static void fill(int[][][][] f, int value) { for (int i = 0; i < f.length; ++i) { fill(f[i], value); } } }}
count方法中找寻点对的方式还很独特,统计了所有经过重心且<=K的点对个数,这样在考虑子问题时,必须要把与重心相连的每个子问题的点对删掉(经过v但不经过重心的点对)。
阅读全文
0 0
- 挑战程序竞赛系列(59):4.6树上的分治法(2)
- 挑战程序竞赛系列(58):4.6树上的分治法(1)
- 挑战程序竞赛系列(60):4.6树上的分治法(3)
- 挑战程序竞赛系列(62):4.6平面上的分治法(2)
- 挑战程序竞赛系列(61):4.6平面上的分治法(1)
- 挑战程序竞赛系列(57):4.6数列上的分治法
- 挑战程序竞赛系列(30):3.4矩阵的幂
- 挑战程序竞赛系列(82):4.3 LCA(2)
- 挑战程序竞赛系列(39):4.1模运算的世界(2)
- 挑战程序竞赛系列(64):4.7字符串上的动态规划(2)
- 挑战程序竞赛系列(81):4.3 LCA(1)
- 挑战程序竞赛系列(1):2.3动态规划
- 挑战程序竞赛系列(4):2.1深度优先搜索
- 挑战程序竞赛系列(5):2.1广度优先搜索
- 挑战程序竞赛系列(6):2.1穷尽搜索
- 挑战程序竞赛系列(9):2.4优先队列
- 挑战程序竞赛系列(10):2.4并查集
- 挑战程序竞赛系列(11):2.5最短路径
- 构造函数和复制构造函数的调用时机
- 开启Spring注解减少XML配置
- 抽象 abstract extends
- Date和String格式互转
- uLua 热更新 创建界面之后按钮点击事件问题
- 挑战程序竞赛系列(59):4.6树上的分治法(2)
- MongoDB serverStatus.globalLock 深入解析
- Spring与SpringMVC整合,以及实现数据库数据的增删查改和分页操作
- VS2017编译DirectX11的Effect框架时,出现C2323错误
- tensorflow的知识点一
- 如何选择数据类型
- 分布式与集群有什么区别
- python-tensorflow(1)C3D代码解析
- Linux文件属性与权限