51Nod 斜率最大

来源:互联网 发布:vsftpd 修改端口 编辑:程序博客网 时间:2024/05/16 05:32

平面上有N个点,任意2个点确定一条直线,求出所有这些直线中,斜率最大的那条直线所通过的两个点。
(点的编号为1-N,如果有多条直线斜率相等,则输出所有结果,按照点的X轴坐标排序,正序输出。数据中所有点的X轴坐标均不相等)

Input
第1行,一个数N,N为点的数量。(2 <= N <= 10000)第2 - N + 1行:具体N个点的坐标,X Y均为整数(-10^9 <= X,Y <= 10^9)
Output
每行2个数,中间用空格分隔。分别是起点编号和终点编号(起点的X轴坐标 < 终点的X轴坐标)
Input示例
51 26 84 45 42 3
Output示例
4 2
Java的运行时限为:3000 ms ,空间限制为:262144 KB
这道题找准思路就会比较容易。

平面上N个点,每两个点都确定一条直线,求出斜率最大的那条直线所通过的两个点(斜率不存在的情况不考虑)。时间效率越高越好。
关于这道题,网上已经给出了解答要点:
3个点A,B,C,把它们的按x坐标排序。假设排序后的顺序是ABC,那么有两种情况:其中k()表示求斜率。
1.ABC共线,则k(AB)=k(BC)=k(AC)
2.ABC不共线,则ABC将形成一个三角形,那么k(AC)<max(k(AB), k(BC))
所以斜率最大的必然是挨在一起的两个点。
所以该道题的基本步骤就是:
1.把N个点按x坐标排序。
2.遍历,求相邻的两个点的斜率,找最大值。
时间复杂度Nlog(N)。
先把这些点按x坐标从小到大排序,斜率最大的两点必然是挨一起的两个点,所以排序O(n* lg n),遍历一次O(n)就够了。

import java.io.PrintWriter;import java.util.ArrayList;import java.util.Scanner;public class Node51_5_MostSlope {public ArrayList<int[]> solve(int n,long[][] zuobiaos){Coordinate[] cs=new Coordinate[n];for(int i=0;i<n;i++){cs[i]=new Coordinate(zuobiaos[i][0], zuobiaos[i][1], i+1);}quickSort(cs, 0, n-1);long maxSlope=Long.MIN_VALUE;ArrayList<int[]> maxSlopeCoordinates=new ArrayList<int[]>();for(int i=0;i<=n-2;i++){Coordinate firstNode=cs[i];Coordinate nextNode=cs[i+1];long thisSlope=(nextNode.y-firstNode.y)/(nextNode.x-firstNode.x);if(thisSlope>maxSlope){maxSlope=thisSlope;maxSlopeCoordinates.clear();int[] theResult=new int[]{firstNode.number,nextNode.number};maxSlopeCoordinates.add(theResult);}else if(thisSlope==maxSlope){int[] theResult=new int[]{firstNode.number,nextNode.number};maxSlopeCoordinates.add(theResult);}}return maxSlopeCoordinates;}//按照x坐标将这些点从小到大排序public void quickSort(Coordinate[] cs, int left, int right) {if (left < right) {int low = left;int high = right;Coordinate pivot = cs[low];while (low < high) {while (low < high && cs[high].x >= pivot.x) {high--;}if (low < high) {cs[low] = cs[high];low++;}while (low < high && cs[low].x <= pivot.x) {low++;}if (low < high) {cs[high] = cs[low];high--;}}cs[low] = pivot;quickSort(cs, left, low - 1);quickSort(cs, low + 1, right);}}public static void main(String[] args) {// TODO Auto-generated method stubScanner in = new Scanner(System.in);PrintWriter out = new PrintWriter(System.out);int n = in.nextInt();//点的数量long[][] zuobiaos=new long[n][2];for(int i=0;i<n;i++){long x=in.nextLong();long y=in.nextLong();long[] the=new long[]{x,y};zuobiaos[i]=the;}in.close();Node51_5_MostSlope node = new Node51_5_MostSlope();ArrayList<int[]> b = node.solve(n,zuobiaos);for(int i=0;i<b.size();i++){int[] ar=b.get(i);out.println(ar[0]+" "+ar[1]);}out.flush();}class Coordinate{long x;long y;int number;public Coordinate(long x,long y,int number){this.x=x;this.y=y;this.number=number;}}}
由于最后输出的是编号,因此编号如果仅仅用数组的索引表示,在排序时就会乱套,因此我新增加了一个坐标点的数据结构,记录每个点的x,y坐标和编号。

另外,需要注意的是class Coordinate不能在public static void main方法中被new,不然的话java会报错No enclosing instance of type Node51_5_MostSlope is accessible. Must qualify the allocation with an enclosing instance of type Node51_5_MostSlope,网上给出如下解答:

main方法中创建内部类的实例时,编译阶段会出现错误。这是由于内部类是动态的(无static关键字修饰),而main方法是静态的,普通的内部类对象隐含地保存了一个引用,指向创建它的外围类对象,所以要在static方法(类加载时已经初始化)调用内部类的必须先创建外部类。即应该这样创建“DanymicTest test = new StaticCallDynamic().new DanymicTest();”其中StaticCallDynamic为外部类,DanymicTest为内部动态类;如果将内部内修改为静态类,可以在main中直接创建内部类实例。