51Nod 斜率最大

平面上有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示例
5
1 2
6 8
4 4
5 4
2 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 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中直接创建内部类实例。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值