平面上有N个点,任意2个点确定一条直线,求出所有这些直线中,斜率最大的那条直线所通过的两个点。
(点的编号为1-N,如果有多条直线斜率相等,则输出所有结果,按照点的X轴坐标排序,正序输出。数据中所有点的X轴坐标均不相等)
第1行,一个数N,N为点的数量。(2 <= N <= 10000) 第2 - N + 1行:具体N个点的坐标,X Y均为整数(-10^9 <= X,Y <= 10^9)
每行2个数,中间用空格分隔。分别是起点编号和终点编号(起点的X轴坐标 < 终点的X轴坐标)
5 1 2 6 8 4 4 5 4 2 3
4 2
平面上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 stub
Scanner 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中直接创建内部类实例。