F - Deer-Proof Fence final

枚举各种情况下的周长,然后dp求出最小值。


#include<iostream>  
#include<stdio.h>  
#include<math.h>  
#include<algorithm>  
#include<vector>  
using namespace std;  
  
struct point  
{  
    int x;  
    int y;  
}points[1100];  
double dp[1<<9];
double d[1<<9];
int n;  
int N;
double ans;
int crossmulty(point a, point b, point c)  
{  
    return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);  
}  
  
int cmp(const void *a, const void *b)  
{  
    if((*(point*)a).y==(*(point*)b).y) return (*(point*)a).x-(*(point*)b).x;  
    return (*(point*)a).y-(*(point*)b).y;  
}  
  
double Distance(point a, point b)  
{  
    return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));  
}  
  
double Graham()  
{  
    double sum=0;  
    int top=1,stack[1100];  
    stack[0]=0, stack[1]=1;  
    for(int i=0;i<n;i++)  
    {  
        while(top>=1 and crossmulty(points[i], points[stack[top]], points[stack[top-1]])>=0)  
        {  
            top--;  
        }  
        stack[++top]=i;  
    }  
    stack[++top]=n-2;  
    int temp=top;  
    for(int i=n-1;i>=0;i--) 
    {  
        while(top>=temp and crossmulty(points[i], points[stack[top]], points[stack[top-1]])>=0)  
        {  
            top--;  
        }  
        stack[++top]=i;  
    }  
    for(int i=0;i<top;i++)  
    {  
        sum+=Distance(points[stack[i]],points[stack[i+1]]); 
    }  
    return sum;
}  
point p[1100];

int main()  
{  
    double r;  
    int cas=1;
    double dis;  
    while(scanf("%d%lf",&N,&r)&&N+r)
    {
    	for(int i=0;i<N;i++)
	        scanf("%d%d",&p[i].x,&p[i].y);
	    for(int i=1;i<(1<<N);i++)
	    {
	    	int t=i;
	    	int k=0;
	    	n=0;
			while(t)
    		{
		    	if(t&1)
		    		points[n++]=p[k];
	    		k++;
	    		t>>=1;
		    }
			qsort(points,n,sizeof(*points),cmp);  
		    dis=2*r*3.1415926;		 
		    dis+=Graham();
		    d[i]=dis;
    	}
    	ans=1000001;
		for(int set = 1; set < (1 << N); ++set)
		{
			dp[set] = 1000001;
			for (int subset = set; subset > 0; (--subset) &= set)
				dp[set]=min(dp[set],dp[set-subset]+d[subset]);
		}
		printf("Case %d: length = %.2lf\n",cas++,dp[(1 << N)-1]);  
    }
	    
    return 0;  
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值