在一个无向图中,计算无序对的数量。

7

问题链接可以在这里找到。

问题陈述

Burger Town是一个由N个特殊交叉口和N-1条路径组成的城市。每对交叉口之间恰好有一条最短路径。第i个交叉口位于(xi,yi),两个交叉口i和j之间的距离定义为出租车几何距离。

Tim最近买了一辆出租车来做出租车司机。他的车非常便宜,但有一个很大的缺点。在需要加油之前,它只能水平行驶H个单位,垂直行驶V个单位。

如果一个顾客想从交叉口i被带到另一个交叉口j,那么只有当这辆车的水平距离之和和竖直距离之和小于或等于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<>();
        }
    }
}

我也尝试了Dijkstra的实现,但也没有成功。

如果有任何建议帮助加快解决方案,将不胜感激。


尝试使用Kruskal算法。 - CodeFox
这个描述有矛盾。在第一段中它说:“每对路口之间恰好有一条最短路径。” 后面又说:“此外,任意两个路口之间都有一条唯一的路径。” 那么它到底是哪个呢? - Jim Mischel
@JimMischel 我没有看到任何矛盾,任意两个连接点之间都有唯一的路径 意味着这是一棵连通树,并且这条唯一路径也是最短路径。 - Pham Trung
@PhamTrung:你说得对。"存在唯一最短路径"这个陈述只是多余的信息。阅读它会让人产生这是某种优化问题(即找到最短路径)的印象。 - Jim Mischel
1个回答

3
这里有一个O(n log^2 n)的解法(在这个问题中已经足够快:我用它成功地被接受了,但我不会在这里发布我的代码,因为我认为理解算法本身比看其实现更有用)。
1. 让我们使用树的重心分解。你可以在这里阅读更多关于它的内容:http://www.ioi2011.or.th/hsc/tasks/solutions/race.pdf
2. 如何合并子树的解决方案?我们可以将每个点表示为一对(x, y),其中x和y是该点到当前根节点的距离,并沿着x和y轴。对于每个点,我们想要计算出满足x1 + x2 <= H和y1 + y2 <= W的其他点的数量,或者说,x1 <= H - x2和y1 <= W - y2。因此,所有针对固定点的“好”点都位于(0, 0, H-x,W-y)矩形中。计算这些点的数量是一个标准问题,可以使用带有treap的扫描线或坐标压缩和二进制索引树,在O(n log n)时间内解决。
3. 这里有一个小问题:我们不应计算来自同一子树的点。我们可以轻松地通过对每个子树运行相同的算法并从答案中减去结果来解决它。
4. 合并步骤在O(n log n)时间内完成。因此,总时间复杂度为O(n log^2 n)。
我知道这个解释不是非常详细,但是我认为使用这里描述的关键思想来想出一个完整的解决方案不应该太难。

谢谢您。我稍后会尝试这个想法 :) - Nilzone-

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接