2014校招 Google在线测试第二场题解 B


题意简要是:在平面上住着一些人,家都是在整数坐标。现在邀请一些人来参加聚会,聚会的地点在这些人中的某一个家。两点的距离为,from (x1, y1) to (x2, y2) is |x1 - x2| + |y1 - y2|.



假设聚会地点选定了,如何计算所有人到这的距离呢?

最直观的就是遍历所有的人,每个都计算一次距离,加起来就可以了。这个算法的复杂度是O(n^2),这个办法可以通过small数据量的。

考虑到 两点的距离分别是横纵坐标的差值绝对值之和,这样就可以在计算的时候对横纵坐标分别计算,然后加起来得到总值。
当只考虑x轴的时候,先把x坐标相同的人加在一块,问题变成某一些坐标上有很多人,计算让这些人全部聚集到某一点的距离和。
就变成这样了:{(x0, p0), (x1, p1), ..., (xm, pm)}, x表示坐标,p表示这个坐标上ren的个数,求在某个坐标时(肯定是x中的某一个)的距离和。

求和的话可以做一些预处理,让计算复杂度变成常数的。先按x排序,然后求出每个坐标到x0的距离和、人数和。得到{(x0, p0, totalP0, totalV0), (x1, p1, totalP1,totalV1), ..., (xm, pm, totalPm, totalVm)},totalPk表示从x0开始到xk的所有人数和,totalVk表示这些人全部聚集到x0的距离和。

然后如何计算所有人到xk的距离和呢?
考虑大于xk的所有人,即totalPm - totalPk, 这些人到x0的距离和是totalVm - totalVk, 然后到xk的距离和再减去xk到x0的距离totalVm - totalVk - (totalPm - totalPk) * (xk - x0)。这样就计算出大于xk的所有人之和。小于xk的呢?按照同样的办法,我们先计算出所有人到xk的距离和、人数和,然后常数的就计算出小于xk的所有人之和了。

对于y轴是一样的计算。

这样通过预处理后,计算所有人到某一个坐标的距离和变成了常数的。O(N)的复杂度就可以通过large数据量了。代码如下:
import java.io.*;
import java.util.*;
import java.util.Map.Entry;


public class HelloWorld {
   
    static class Node implements Comparable<Node> {
        long location;
        long person;
        long leftPerson;
        long leftValue;
        long rightPerson;
        long rightValue;
       
        Node () {
        }
        Node(long x) {
            location = x;
        }
       
        @Override
        public int compareTo(Node o) {
            long ret = location - o.location;
            if (ret == 0) return 0;
            return ret < 0? -1 : 1;
        }
    }
   
    public static void main(String[] args) {
        try {
//            BufferedReader br = new BufferedReader(new FileReader("D:/codejam/a.txt"));
//            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
           
//            BufferedReader br = new BufferedReader(new FileReader("D:/codejam/B-small-practice.in"));
//            BufferedWriter bw = new BufferedWriter(new FileWriter("D:/codejam/B-small-result.txt"));
//            BufferedReader br = new BufferedReader(new FileReader("D:/codejam/B-small-attempt1.in"));
           
            BufferedReader br = new BufferedReader(new FileReader("D:/codejam/B-large-practice.in"));
            BufferedWriter bw = new BufferedWriter(new FileWriter("D:/codejam/B-large-result.txt"));

            String line;
           
            line = br.readLine();
            int T = Integer.parseInt(line);
           
            for (int cas = 1; cas <= T; cas++) {
                Map<Long, Long> xMap = new TreeMap<Long, Long>();
                Map<Long, Long> yMap = new TreeMap<Long, Long>();
               
                line = br.readLine();
                int B = Integer.parseInt(line);
               
                long[] all = new long[1000000 * 2];
                int len = 0;
               
                for (int i = 0; i < B; i++) {
                    line = br.readLine();
                    String[] tmp = line.split(" ");
                    long sx = Long.parseLong(tmp[0]);
                    long sy = Long.parseLong(tmp[1]);
                    long nx = Long.parseLong(tmp[2]);
                    long ny = Long.parseLong(tmp[3]);
                    for (long x = sx; x <= nx; x++) {
                        long value = 0;
                        if (xMap.containsKey(x)) {
                            value = xMap.get(x) + ny - sy + 1;
                        } else {
                            value = ny-sy+1;
                        }
                        xMap.put(x, value);
                    }
                    for (long y = sy; y <= ny; y++) {
                        long value = 0;
                        if (yMap.containsKey(y)) {
                            value = yMap.get(y) + nx - sx + 1;
                        } else {
                            value = nx - sx + 1;
                        }
                        yMap.put(y, value);
                    }
                    for (long x = sx; x <= nx; x++)
                        for (long y = sy; y <= ny; y++) {
                            all[len++] = x;
                            all[len++] = y;
                        }
                }
               
                ArrayList<Node> xList = new ArrayList<Node>();
                ArrayList<Node> yList = new ArrayList<Node>();
                build(xMap, xList);
                build(yMap, yList);
               
               
                long ret = Long.MAX_VALUE;
                long rx = 0;
                long ry = 0;
                for (int i = 0; i < len ;i+=2) {
                    long x = all[i];
                    long y = all[i+1];
                   
                    long tmp = 0;
                    tmp += compute(xList, x);
                    tmp += compute(yList, y);
                   
                    if (tmp < ret || (tmp == ret && (x < rx || (x == rx && y < ry)))) {
                        ret = tmp;
                        rx = x;
                        ry = y;
                    }
                }
                bw.write("Case #" + cas +": " + rx + " " + ry + " " + ret);
                bw.newLine();
                bw.flush();
            }
           
            br.close();
            bw.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static long compute(ArrayList<Node> xList, long x) {
        int n = xList.size();
        long ret = 0;
        int lo = Collections.binarySearch(xList, new Node(x));
        Node last = xList.get(n-1);
        Node first = xList.get(0);
        Node node = xList.get(lo);
        ret += last.leftValue - node.leftValue - (last.leftPerson - node.leftPerson) * (node.location - first.location);
        ret += first.rightValue - node.rightValue - (first.rightPerson - node.rightPerson) * (last.location - node.location);
        return ret;
    }

    private static void build(Map<Long, Long> xMap, ArrayList<Node> xList) {
        Iterator<Entry<Long, Long>> iter = xMap.entrySet().iterator();
        while (iter.hasNext()) {
            Entry<Long, Long> entry = iter.next();
            Node x = new Node();
            x.location = entry.getKey();
            x.person = entry.getValue();
            xList.add(x);
        }
       
        Node node = xList.get(0);
        node.leftPerson = node.person;
        node.leftValue = 0;
        int n = xList.size();
        long firstLocation = node.location;
        for (int i = 1; i < n; i++) {
            node = xList.get(i);
            node.leftPerson += xList.get(i-1).leftPerson + node.person;
            node.leftValue += xList.get(i-1).leftValue + (node.person * (node.location - firstLocation));
        }
        node = xList.get(n-1);
        node.rightPerson = node.person;
        node.rightValue = 0;
        long lastLocation = node.location;
        for (int i = n - 2; i>=0; i--) {
            node = xList.get(i);
            node.rightPerson += xList.get(i+1).rightPerson + node.person;
            node.rightValue += xList.get(i+1).rightValue + (node.person * (lastLocation - node.location));
        }
    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值