圈奶牛+礼品包裹解决凸包问题+枚举相邻两点长度之和

P2742 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows

题目描述

农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏。他建造的围栏必须包括他的奶牛喜欢吃草的所有地点。对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度。

输入输出格式

输入格式:

 

输入数据的第一行包括一个整数 N。N(0 <= N <= 10,000)表示农夫约翰想要围住的放牧点的数目。接下来 N 行,每行由两个实数组成,Xi 和 Yi,对应平面上的放牧点坐标(-1,000,000 <= Xi,Yi <= 1,000,000)。数字用小数表示。

 

输出格式:

 

输出必须包括一个实数,表示必须的围栏的长度。答案保留两位小数。

 

输入输出样例

输入样例#1: 复制

4
4 8
4 12
5 9.3
7 8

输出样例#1: 复制

12.00

说明

题目翻译来自NOCOW。

分析:凸包+求相邻线段长度(主要是凸包的求法)

代码:

/**
 * 
 * 凸包:求周长
 * 奶牛栅栏多长
 * AC通过
 * 
 */
import java.util.ArrayList;
import java.util.Scanner;

public class Main {
	
	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();
			
		}
		baoguo();
		double s=0;
		for(int i=1;i<a.size();i++)
		{
			s+=Distance(a.get(i)-1,a.get(i));
		}
		s+=Distance(a.get(0),a.get(a.size()-1));
		
		System.out.printf("%.2f",s);
		
		
	}
	//给我Point点的位置即可
	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 Math.sqrt((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++)
			{
				if(i!=index&&(k==-1||(Direction(index,i,k)>0||Direction(index,i,k)==0&&(Distance(index,k)<Distance(index,i)))))
				{
					k=i;
				}
			}
			if(k==tmp)
				break;
			index=k;
		}
	}
	
	
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值