挑战程序竞赛系列(61):4.6平面上的分治法(1)
来源:互联网 发布:js文件加载失败 编辑:程序博客网 时间:2024/06/05 02:29
挑战程序竞赛系列(61):4.6平面上的分治法(1)
- 传送门:Uva 10245: The Closest Pair Problem
- 传送门:POJ 3714: Raid
Uva 10245: The Closest Pair Problem
思路:
分治,参考《挑战》P365:
利用分治后左平面和右平面的最小d来限制第二种情况的查询,绝了。关于第二种情形的算法采用平面扫描法,但前提y需要排序。
注意一些细节:比如如何确定矩形y的范围,先来看看代码:
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.ArrayList;import java.util.Arrays;import java.util.List;import java.util.StringTokenizer;public class Main{ String INPUT = "./data/judge/201709/U0245.txt"; public static void main(String[] args) throws IOException { new Main().run(); } static final int MAX_N = 10000 + 16; static final double INF = 1e4; class Pair implements Comparable<Pair>{ double x; double y; Pair(double x, double y){ this.x = x; this.y = y; } @Override public String toString() { return x + " " + y; } @Override public int compareTo(Pair that) { if (this.x != that.x) return Double.compare(this.x, that.x); return Double.compare(this.y, that.y); } } Pair[] tmp = new Pair[MAX_N]; double solve(Pair[] p, int l, int r) { if (r - l <= 1) return 12341234; int mid = (l + r) / 2; double x = p[mid].x; double d = Math.min(solve(p, l, mid), solve(p, mid, r)); int k = 0; int ll = l, rr = mid; while (ll < mid && rr < r) { if (p[ll].y < p[rr].y) tmp[k++] = p[ll++]; else tmp[k++] = p[rr++]; } while (ll < mid) tmp[k++] = p[ll++]; while (rr < r) tmp[k++] = p[rr++]; for (int i = l; i < r; ++i) p[i] = tmp[i - l];// for (int i = l, j = mid, k = l; k < r;) {// if (j >= r || i < mid && p[i].y < p[j].y) tmp[k++] = p[i++];// else tmp[k++] = p[j++];// }// for (int i = l; i < r; ++i) p[i] = tmp[i]; List<Pair> b = new ArrayList<>(); for (int i = l; i < r; ++i) { if (Math.abs(p[i].x - x) >= d) continue; for (int j = b.size() - 1; j >= 0; --j) { double dx = p[i].x - b.get(j).x; double dy = p[i].y - b.get(j).y; if (Math.abs(dy) >= d) break; d = Math.min(d, Math.sqrt(dx * dx + dy * dy)); } b.add(p[i]); } return d; } void read() { while (true) { int N = ni(); if (N == 0) break; Pair[] points = new Pair[N]; for (int i = 0; i < N; ++i) { double x = nd(); double y = nd(); points[i] = new Pair(x, y); } Arrays.sort(points); double ans = solve(points, 0, N); if (ans >= INF) out.println("INFINITY"); else { out.printf("%.4f\n", 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); } } }}
此处:
List<Pair> b = new ArrayList<>(); for (int i = l; i < r; ++i) { if (Math.abs(p[i].x - x) >= d) continue; for (int j = b.size() - 1; j >= 0; --j) { double dx = p[i].x - b.get(j).x; double dy = p[i].y - b.get(j).y; if (Math.abs(dy) >= d) break; d = Math.min(d, Math.sqrt(dx * dx + dy * dy)); } b.add(p[i]); }
纠结了很久,注意第二个循环的break,使用break,说明dy >= d
的情况都不需要比较,那么必须满足当前点和之前最大的那些点进行比较,continue的话,就与顺序无关,因为遍历了所有情况,但估计数据量一大就超时,根据书上的定义该for循环不会超过6次,可以认为是常数级的。
POJ 3714: Raid
求能量站和人之间的最短顶点对。
思路:
多了个限制,人与能量站之间的最短距离,那么在分治求解时,当且仅当遇到两个顶点分别是人和能量站时进行最短距更新即可。
代码如下:
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.ArrayList;import java.util.Arrays;import java.util.List;import java.util.StringTokenizer;public class Main{ String INPUT = "./data/judge/201709/P3714.txt"; public static void main(String[] args) throws IOException { new Main().run(); } static final int MAX_N = 100000 + 16; static final int INF = 0x3f3f3f3f; class Pair implements Comparable<Pair>{ double x; double y; boolean man; Pair(double x, double y, boolean man){ this.x = x; this.y = y; this.man = man; } @Override public String toString() { return x + " " + y; } @Override public int compareTo(Pair o) { return x > o.x ? -1 : 1; } } Pair[] tmp = new Pair[2 * MAX_N]; double solve(Pair[] p, int l, int r) { if (r - l <= 1) return INF; int m = (l + r) / 2; double x = p[m].x; double d = Math.min(solve(p, l, m), solve(p, m, r)); // merge for (int i = l, j = m, k = l; k < r;) { if (j >= r || i < m && p[i].y < p[j].y) tmp[k++] = p[i++]; else tmp[k++] = p[j++]; } for (int i = l; i < r; ++i) p[i] = tmp[i]; List<Pair> b = new ArrayList<Pair>(); for (int i = l; i < r; ++i) { if (Math.abs(p[i].x - x) >= d) continue; for (int j = b.size() - 1; j >= 0; --j) { double dx = p[i].x - b.get(j).x; double dy = p[i].y - b.get(j).y; if (p[i].man ^ b.get(j).man) { if (Math.abs(dy) >= d) break; d = Math.min(d, Math.sqrt(dx * dx + dy * dy)); } } b.add(p[i]); } return d; } void read() { int T = ni(); while (T --> 0) { int N = ni(); Pair[] points = new Pair[2 * N]; for (int i = 0; i < N; ++i) { points[i] = new Pair(nd(), nd(), false); } for (int i = 0; i < N; ++i) { points[i + N] = new Pair(nd(), nd(), true); } Arrays.sort(points); out.printf("%.3f\n", solve(points, 0, 2 * N)); } } 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); } } }}
阅读全文
0 0
- 挑战程序竞赛系列(61):4.6平面上的分治法(1)
- 挑战程序竞赛系列(62):4.6平面上的分治法(2)
- 挑战程序竞赛系列(57):4.6数列上的分治法
- 挑战程序竞赛系列(58):4.6树上的分治法(1)
- 挑战程序竞赛系列(59):4.6树上的分治法(2)
- 挑战程序竞赛系列(60):4.6树上的分治法(3)
- 挑战程序竞赛系列(87):3.6平面扫描(1)
- 挑战程序竞赛系列(63):4.7字符串上的动态规划(1)
- 挑战程序竞赛系列(88):3.6平面扫描(2)
- 挑战程序竞赛系列(89):3.6平面扫描(3)
- 挑战程序竞赛系列(64):4.7字符串上的动态规划(2)
- 挑战程序竞赛系列(65):4.7字符串上的动态规划(3)
- 挑战程序竞赛系列(30):3.4矩阵的幂
- 挑战程序竞赛系列(81):4.3 LCA(1)
- 挑战程序竞赛系列(1):2.3动态规划
- 挑战程序竞赛系列(38):4.1模运算的世界(1)
- 挑战程序竞赛系列(82):4.3 LCA(2)
- 挑战程序竞赛系列(4):2.1深度优先搜索
- Js slice()方法与substr和substring的区别
- 基于ISO镜像构建Yum本地源
- hdu 6166(随机概率dijkstra)
- 彻底弄懂css中单位px和em,rem的区别
- JSON.stringify(),JSON.parse(),toJSON()方法使用
- 挑战程序竞赛系列(61):4.6平面上的分治法(1)
- matplotlib坐标轴中文乱码问题解决
- 状态管理工具vuex初识
- solr查询条件过多异常
- DrawerLayout侧拉菜单+TabLayou导航栏
- WPF实现半透明背景的弹框
- 反转链表
- 在Linux的PC上挂载jffs2根文件系统映像
- Android Studio导入第三方类库、jar包和so库