计算无方向图

时间:2015-04-23 15:35:03

标签: java algorithm optimization timeout

可以在 here

找到问题的链接
  

问题陈述

     

汉堡镇是一个由N个特殊交汇点和N-1组成的城市   途径。每对之间只有一条最短的路径   路口。交叉点i位于(xi,yi)和之间的距离   两个交叉点i,j由Taxicab几何定义。

     蒂姆最近提供了一辆出租车作为出租车司机。他的   车很便宜,但有一个很大的缺陷。它只能驱动H.   加油前水平单位和垂直V单位。

     

如果客户想要从一个路口i带到另一个路口   交叉点j,那么这辆车只能驱动路线,iff   水平距离和垂直距离之和的总和   该路径分别小于或等于H和V.

     

此外,任何两个交叉点之间都有一条独特的路径。

     

现在他想到将车辆还给卖家。   但他首先想知道,它是否值得。这就是他想要的原因   知道无序对(i,j)的数量,使其不是   可以将客户从路口i带到路口j。

     

约束

     

2≤N≤10^ 5

     

0≤H,V≤10^ 14

     

0≤xi,yi≤10^ 9

我用递归解决了这个问题。但是在一些测试用例中,我的代码已超时。

import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;

public class Solution {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int N = in.nextInt();
        long H = in.nextLong();
        long V = in.nextLong();
        List<Vertex> vertex = new ArrayList<>();

        for (int i=0; i < N; i++) {
            Vertex vx = new Vertex(in.nextLong(), in.nextLong());
            vertex.add(vx);
        }
        for (int i=0; i < N-1; i++) {
            int fromPath = in.nextInt()-1;
            int toPath = in.nextInt()-1;
            vertex.get(fromPath).neighbours.add(vertex.get(toPath));
            vertex.get(toPath).neighbours.add(vertex.get(fromPath));
        }

        long count = 0;

        for (int i=0; i < N; i++) {
            count += (N - findUnorderedPairs(vertex.get(i), null, 0, 0, H, V));
        }

        System.out.println(count/2);
        int temp = 0;

    }

    private static long findUnorderedPairs(Vertex vertex, Vertex previousVertex, long hor, long vert, long H, long V) {
        if (hor > H || vert > V) {
            return 0;
        }

        long result = 1;

        for (Vertex v : vertex.neighbours) {
                result += (v != previousVertex) ? findUnorderedPairs(v, vertex, hor + Math.abs(vertex.x - v.x), vert + Math.abs(vertex.y - v.y), H, V) : 0;

        }

        return result;
    }

    private static class Vertex {
        private long x;
        private long y;
        public ArrayList<Vertex> neighbours;

        public Vertex(long x, long y) {
            this.x = x;
            this.y = y;
            neighbours = new ArrayList<>();
        }
    }
}

我也尝试过Dijkstras的实现,但也没有运气。

任何关于如何实现更快速解决方案的建议都会受到赞赏。

1 个答案:

答案 0 :(得分:3)

这是一个O(n log^2 n)解决方案(这个问题足够快了:我设法使用它来接受,但我不会在这里发布我的代码因为我认为理解算法本身更有用而不是看它的实现。)

  1. 让我们使用树的质心分解。您可以在此处详细了解:http://www.ioi2011.or.th/hsc/tasks/solutions/race.pdf

  2. 如何合并子树的解决方案?我们可以将每个点表示为一对(x, y),其中xyxy轴从此点到当前根的距离。对于每个点,我们希望计算x1 + x2 <= Hy1 + y2 <= W等其他点的数量,或者换句话说x1 <= H - x2y1 <= W - y2。因此,所有&#34;好&#34;固定点的点位于(0, 0, H - x, W - y)矩形中。计算这些点的数量是一个标准问题,可以使用带有treap(或坐标压缩和二进制索引树)的扫描线在O(n log n)时间内解决。

  3. 这里有一个小问题:我们不应该计算来自同一子树的点数。我们可以通过为每个子树运行相同的算法并从答案中减去结果来轻松修复它。

  4. 合并步骤在O(n log n)时间完成。因此,总时间复杂度为O(n log^2 n)

  5. 我知道这个解释不是很详细,但在我看来,使用这里描述的关键思想来制定一个完整的解决方案并不困难。