选美赛
时间限制: 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)
资源
分析:凸包+暴力求解两点线段最长
凸包问题有两种方法:
- 礼品包裹算法+暴力两点线段最长
- 葛立恒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;
}
}
新手学习,请多指教