题目大意:
要在一座城堡周围建围墙,要求用料最省。围墙距城堡不得小于 距离 L。
浅析:
题目要求用料最省,求围墙长度。因此只要找一个最小的多边形能够围住城堡即可。因此是一个求凸包周长的问题。
距离不得小于L。因此凸包顶点会形成扇形。各扇形聚在一起形成了一个圆。
所以所求周长 = 凸包周长 + 一个圆的周长。
因为这个题数据量不大,graham中的极角排序我还不会,所以用了卷包裹的方法来求凸包。
卷包裹法最后得到的点并不一定是凸包顶点,所以每确定一个点,一定要判断一下是不是终点。(即判断它的后继点是否在凸包起点的左侧,如果是,那这个点就是凸包终点,与起点连载一起形成凸包)。
卷包裹过程中依次更新周长sum值。然后加上起点终点的长度,再加上圆的周长,就得到了所求值。
我的代码如下:(供参考)
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<math.h>
#define Pi 3.1415926535898
#define inf 10001
struct Point
{
int x, y;
int mark;
}a[1010];
int left(int minp, int num, int i)
{
return (a[num].x-a[minp].x)*(a[i].y-a[minp].y)-(a[i].x-a[minp].x)*(a[num].y-a[minp].y);
}
double dis(int minp, int num, int i)
{
return sqrt( (a[i].x-a[minp].x)*(a[i].x-a[minp].x)+(a[i].y-a[minp].y)*(a[i].y-a[minp].y) ) - sqrt( (a[num].x-a[minp].x)*(a[num].x-a[minp].x)+(a[num].y-a[minp].y)*(a[num].y-a[minp].y) );
}
double dist(int minp, int num)
{
return sqrt( (a[num].x-a[minp].x)*(a[num].x-a[minp].x)+(a[num].y-a[minp].y)*(a[num].y-a[minp].y) );
}
int min(int m, int n)
{
if(m<n) return m;
return n;
}
int max(int m, int n)
{
if(m>n) return m;
return n;
}
int online(int minp, int num, int tmp)
{
if( a[num].x >= min(a[minp].x, a[tmp].x) && a[num].x<=max(a[minp].x, a[tmp].x) )
return 1;
return 0;
}
int main()
{
int i, n, l, minx=inf, miny=inf, minp, time, num, tmp;
double sum=0.0;
scanf("%d%d", &n, &l);
for(i=0; i<n; i++)
{
scanf("%d%d", &a[i].x, &a[i].y);
a[i].mark = 1;
if(a[i].y<miny || (a[i].y==miny && a[i].x<minx) )
{
miny = a[i].y;
minx = a[i].x;
minp = i;
}
}
tmp = minp;
a[minp].mark = 0;
time = 0;
while(time!=n-1)
{
//卷包裹法求下一个凸包顶点
for(i=0; i<n; i++)
{
if(a[i].mark)
{
num=i;
break;
}
}
for(i=0; i<n; i++)
{
if(a[i].mark && i!=num && (left(minp, num, i)<0||(left(minp, num, i)==0&&dis(minp, num, i)<0)))
{
num=i;
}
}
//判断 minp点是不是凸包终点,如果是,则与其连接的点为起点
if(minp!=tmp && (left(minp, num, tmp) < 0 || (left(minp, num, tmp)==0 && online(minp, num, tmp) ) ) )
{
num=tmp;
break;
}
sum = sum + dist(minp, num);
minp = num;
a[num].mark = 0; //标记为凸包顶点
time++; //最坏情况下循环次数time = n-1
}
//printf("sum=%lf\n", sum);
sum += (Pi * l * 2 + dist(minp, tmp)); //凸包周长(+起点和终点的距离)+一个圆周长
printf("%.0f\n", sum);
//system("pause");
return 0;
}