选美赛+礼品包裹解决凸包问题+枚举最大线段+java解决

 选美赛

时间限制: 3000MS

 

内存限制: 65536K

提交总数: 44742

 

接受: 13785

描述

Bessie,Farmer John的奖品牛,刚刚在牛美女比赛中获得第一名,获得了“牛小姐世界”的称号。因此,Bessie将参观世界各地的N(2 <= N <= 50,000)农场,以便在农民和他们的奶牛之间传播商誉。为简单起见,世界将表示为二维平面,其中每个农场位于一对整数坐标(x,y),每个坐标具有-10,000 ... 10,000范围内的值。没有两个农场共享同一对坐标。 

尽管Bessie直接在两对农场之间直线旅行,但是一些农场之间的距离可能很大,所以她想带一个装满干草的行李箱,这样她就可以在旅程的每一段都吃足够的食物。由于Bessie在她访问的每个农场重新装满行李箱,她想确定她可能需要旅行的最大距离,因此她知道她必须携带的行李箱大小。通过计算所有农场对的最大距离来帮助Bessie。 

输入

*第1行:单个整数,N 

*行2..N + 1:两个以空格分隔的整数x和y,指定每个农场的坐标 

产量

*第1行:一个整数,是距离彼此最远的一对农场之间的平方距离。 

样本输入

4

0 0

0 1

1 1

1 0

样本输出

2

暗示

农场1(0,0)和农场3(1,1)具有最长距离(平方根2) 

资源

USACO 2003秋季

 

分析:凸包+暴力求解两点线段最长

 

凸包问题有两种方法:

  1. 礼品包裹算法+暴力两点线段最长
  2. 葛立恒Graham+旋转卡壳

这里主要就是用礼品包裹+暴力两点线段最长:

贴代码:

1、第一种方式:

import java.util.Scanner;
public class Main {
	//写一个内部类
	public static class Point
	{
		double x;
		double y;
		public Point()
		{
			
		}
		public Point(double x1,double y1)
		{
			x=x1;
			y=y1;
		}
		@Override
		public String toString() {
			return "Point [x=" + x + ", y=" + y + "]";
		}
	}
	
	static double Distance(Point p1,Point p2)
	{
		return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);
	}
	
	static double Det(Point p1,Point p2)
	{
		return  p1.x*p2.y-p1.y*p2.x;
	}
	
	static int Direction(Point p0,Point p1,Point p2)
	{
		double d=Det(new Point(p1.x-p0.x,p1.y-p0.y),new Point(p2.x-p0.x,p2.y-p0.y));
	
		if(d==0) return 0;
		else if(d>0) return 1;
		else return -1;
	}
	
	//判断前者ajai在ajak的顺时针方向上返回真或者三点共线返回距离较远的ajai则为真
	static boolean cmp(Point aj,Point ai,Point ak)
	{
		int d=Direction(aj,ai,ak);
		if(d==0)
			return Distance(aj,ai)>Distance(aj,ak);
		else if(d>0)
			return true;
		else
			return false;
	}
	
	static void baoguo(Point a[])
	{
		int i,j,k,temp;
		j=0;
		//找到最左最下的点
		for(i=1;i<a.length;i++)
		{
			if(a[i].x<a[j].x||(a[i].x==a[j].x&&a[i].y<a[j].y))
				j=i;
		}
		temp=j;//标记
		
		while(true)
		{
			k=-1;
			b[count]=a[j];
			count=count+1;
			
			for(i=0;i<a.length;i++)
				if(i!=j&&(k==-1||cmp(a[j],a[i],a[k])))
					k=i;
			if(k==temp) break;
			j=k;
		}
	}
	
	//存凸点
	static Point b[];
	static int count=0;
	
	public static void main(String[] args) {
	
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		Point a[]=new Point[n];
		b=new Point[n];
		for(int i=0;i<n;i++)
		{
			a[i]=new Point();
			a[i].x=sc.nextDouble();
			a[i].y=sc.nextDouble();
		}
		
		baoguo(a);

		//求最长线段
		double max=0;
		for(int i=0;i<count;i++)
		{
			for(int j=i+1;j<count;j++)
			{
				max=Math.max(max, Distance(b[i],b[j]));
			}
		}
		System.out.println((int)max);
	}
}

2、第二种方式:


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
	
	//存放点的坐标x,y
	static double x[];
	static double y[];
	static int n;
	//这是存凸包点的一种方式
//	static int count;//表示凸包数组中有count个元素
//	static int ch[]=new int [n];
	//这是存凸包点的第二种方式
	static ArrayList<Integer> a=new ArrayList();
	
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		n=sc.nextInt();
		x=new double[n];
		y=new double[n];
		//获取数据
		for(int i=0;i<n;i++)
		{
			x[i]=sc.nextDouble();
			y[i]=sc.nextDouble();
			
		}
		//调用礼品包裹算法生成凸包点集a(a存的书凸包点所在的下标)
		baoguo();
		//自定义求最大值的方法
		System.out.println((int)Max());

	}
	//这个叉乘很重要
	//叉乘ab在前,ac在后,前者ab在ac顺时针方向上则结果>0
	//Direction(a,b,c)==0,则a,b,c三点共线
	//Direction(a,b,c)<0,则ab在ac的逆时针方向上
	static int Direction(int a,int b,int c)
	{
		double d=(x[b]-x[a])*(y[c]-y[a])-(x[c]-x[a])*(y[b]-y[a]);
		if(d==0) return 0;
		else if(d>0) return 1;
		else return -1;
	}
	//两点间距离
	static double Distance(int a,int b)
	{
		return (x[b]-x[a])*(x[b]-x[a])+(y[b]-y[a])*(y[b]-y[a]);
	}
	//求凸包的算法之一---》礼品包裹算法
	static void baoguo()
	{
		//选最左最下的点
		int index=0;//标记最左最小下标
		double min=x[0];
		int tmp;
		int k;
		//选择最左最下的点最为原点
		for(int i=0;i<n;i++)
		{
			if(min>x[i]||min==x[i]&&y[index]>y[i])
			{
				min=x[i];
				index=i;
			}
		}
		tmp=index;
		//礼品包裹算法的核心部分
		while(true)
		{
			k=-1;
			a.add(index);
			for(int i=0;i<n;i++)
			{
				//以原点为中心按顺时针找最后一个点,加入凸包点集a中,
				//当然若顺时针找的时候出现两个点则选择距离较远的加入凸包点集
				if(i!=index&&(k==-1||(Direction(index,i,k)>0||Direction(index,i,k)==0&&(Distance(index,k)<Distance(index,i)))))
				{
					k=i;
				}
			}
			//找一圈回到最初原点则结束while
			if(k==tmp)
				break;
			index=k;
		}
	}
	//暴力求两点最大距离--》没啥好说的
	static double Max()
	{
		int i,j;
		double d,maxdist=0.0;
		for(i=0;i<a.size();i++)
		{
			for(j=i+1;j<a.size();j++)
			{
				d=Distance(a.get(i),a.get(j));
				if(d>maxdist)
				{
					maxdist=d;
				}
			}
		}
		return maxdist;
	}
}

新手学习,请多指教

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值