分治求凸包周长

POJ 1113题意:
     从前有一个吝啬的国王要求他的总设计师在他的城堡周围建一道围墙。这国王非常吝啬,以至于他没有听总设计师的建一个拥有外形漂亮又高大的砖头塔楼的围墙的建议,而是要求用最少的石头和劳工围着整个城堡建围墙,但是要求围墙必须远离城堡一定的距离。要是国王发现发现设计师用了超过建造围墙所需要的材料,那么这个设计师的脑袋将保不住了。而且,国王要求设计师马上拿出一个建墙的计划,列出建造围墙所需要的最少的材料。你的任务是去帮助这个可怜的设计师保住他的性命,请写一个程序算出建造满足国王要求的围墙的最小的长度。这个任务事实上稍微有点简单,因为国王的城堡是一个多边形的,除开顶点处,其他的地方不会相交,并且位于平坦的地面上,设计师早已画好了一个笛卡尔坐标系,而且精确地计算出了城堡中每一个点的坐标。



Input
第一行包括两个整数,N,L,第一个整数是点的个数,第二个整数是围墙必须远离城堡的距离。接下来n行,每行两个数{中间一个空格}表示每一个点的坐标。所有的点各不相同。

Output
输出一个整数,即围墙的长度。答案四舍五入

样例:
Sample Input

9 100
200 400
300 400
300 300
400 300
400 400
500 400
500 200
350 200
200 200
Sample Output

1628

思路与前面一篇文章一样,所以写起来很流畅。

JAVA AC代码:


import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Sot_fzh
 */
public class Main1113 {
    static class Point{
        int x,y;
        public Point(int x,int y){
            this.x=x;
            this.y=y;
        }
    }
    static class Line{
        Point p1;
        Point p2;
        public Line(Point start,Point end){
            p1=start;
            p2=end;
        }
        public double size(){  
            return Math.sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
        }
    }
   
   
    public static double getArea(Point p1,Point p2,Point p3){
        return p1.x*p2.y+p1.y*p3.x+p2.x*p3.y-p2.y*p3.x-p1.y*p2.x-p1.x*p3.y;
    }
   
    static ArrayList<Line>lines=new ArrayList();
    public static void main(String[] args) {
        Scanner scan=new Scanner(System.in);
        int num=scan.nextInt();
        int r=scan.nextInt();
        ArrayList<Point>set=new ArrayList();
        for(int i=0;i<num;i++){
            int x=scan.nextInt();
            int y=scan.nextInt();
            set.add(new Point(x,y));
        }
        ArrayList<Point>left=new ArrayList();
        ArrayList<Point>right=new ArrayList();
        Collections.sort(set,new Comparator() {

            @Override
            public int compare(Object o1, Object o2) {
               Point p1=(Point)o1;
               Point p2=(Point)o2;
               return p1.x>p2.x?1:0;
            }
        });
        Point p1=set.get(0);
        Point p2=set.get(num-1);       
        for(int i=0;i<set.size();i++){
            Point p3=set.get(i);
            if(getArea(p1,p2,p3)>0){
                left.add(p3);
            }else if(getArea(p1,p2,p3)<0){
                right.add(p3);
            }           
        }
        divide(p1,p2,left);
        divide(p2,p1,right);
        double sum=2*Math.PI*r;
        for(int i=0;i<lines.size();i++){
            double lens=lines.get(i).size();
            sum+=lens;
        }
        System.out.printf("%.0f\n",sum);
       
    }
   
    public static void divide(Point p1,Point p2,ArrayList<Point>set){
        if(set.isEmpty()){
            lines.add(new Line(p1,p2));
            return;
        }
        Point top=null;
        double max=0;
        for(int i=0;i<set.size();i++){
            Point p3=set.get(i);
            double lens=getArea(p1,p2,p3);
            if(max<lens){
                top=p3;
                max=lens;
            }
        }
        ArrayList<Point>s1=new ArrayList();
        ArrayList<Point>s2=new ArrayList();
        for(int i=0;i<set.size();i++){
            Point p3=set.get(i);
            if(getArea(p1,top,p3)>0){
                s1.add(p3);
            }else if(getArea(top,p2,p3)>0){
                s2.add(p3);
            }           
           
        }
        divide(p1,top,s1);
        divide(top,p2,s2);
       
       
    }
   
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值