Problem Address:http://poj.org/problem?id=1113
【前言】
我还是觉得这道题有点问题的。
正确答案是算出凸包再加上以L为半径的圆的周长。
但是,我觉得事实并非如此。
因为在有些凹进去的地方是需要把围墙造到里面去的,那种情况的围墙长度会更短。
不过既然答案是这样,那就只好这样做了。
【思路】
简单的凸包。
答案为凸包上点所围成的长度加上以L为半径的圆的周长。
因为需要围墙距离城堡L的距离,所以在拐角处需要画圆。
对于一个封闭的凸多边形,所有弧加起来就是一个圆。
画画就知道。
其实是刚好想学凸包,所以就找了道题来做。
具体的凸包看看算法导论,里面写的很清楚,实现也比较容易。
不要注意的是关于极角和左转的计算。
此外,输出时应该用printf("%.0lf\n", sum)。
一开始也成printf("%d\n", (int)sum),返回了WA。
后来找了一组1000个的数据,居然自己的程序跑不出来。
改了之后就AC了。
前者是四舍五入,后者是直接去尾。
【代码】
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1000;
const double pi = 3.141592653;
struct point
{
int x;
int y;
}pt[maxn+5], q[maxn+5];
bool cmp(const point &a, const point &b)//比较极角
{
int ax = a.x-pt[0].x;
int ay = a.y-pt[0].y;
int bx = b.x-pt[0].x;
int by = b.y-pt[0].y;
int t = ax*by - bx*ay;
if (t<0) return 0;
else if (t>0) return 1;
else return (ax*ax+ay*ay)>(bx*by+by*by);
}
int main()
{
int n, l;
int i, k;
point temp;
scanf("%d %d", &n, &l);
for (i=0; i<n; i++)
scanf("%d %d", &pt[i].x, &pt[i].y);
for (i=1, k=0; i<n; i++)//得到左下方坐标k
{
if (pt[i].y<pt[k].y)
{
k = i;
}
else if (pt[i].y==pt[k].y)
{
if (pt[i].x<pt[k].x)
{
k = i;
}
}
}
temp = pt[0];
pt[0] = pt[k];
pt[k] = temp;
sort(pt+1, pt+n, cmp);//按极角排序
q[0] = pt[0];//p0,p1,p2入栈
q[1] = pt[1];
q[2] = pt[2];
int top = 3;
pt[n] = pt[0];
for (i=3; i<=n; i++)
{
while((pt[i].x-q[top-2].x)*(q[top-1].y-q[top-2].y)-(q[top-1].x-q[top-2].x)*(pt[i].y-q[top-2].y)>=0 && top>2)//判断左转,等于零去除共线
{
top--;
}
q[top] = pt[i];
top++;
}
double sum = 2*pi*l;
for (i=1; i<top; i++)
{
sum += sqrt((double)((q[i].x-q[i-1].x)*(q[i].x-q[i-1].x)+(q[i].y-q[i-1].y)*(q[i].y-q[i-1].y)));//计算距离
}
printf("%.0lf\n", sum);
return 0;
}