标签:
给n个点 连出一个凸包 然后在凸包外筑墙 要求墙与凸包每一处的距离都>=l 问需要建的最短的墙长
乍一看挺难 画画图就能看出来 凸包外建距离l的墙 其实就是在凸包每个顶点处 以顶点为圆心 做半径为l的弧 做到两侧半径与点的两边平行即可 然后把这些弧都用直线衔接 就是最短墙长
这样还不好求 呢把弧拿出来呢 其实就相当于把整个凸包作为一个点 以该点为圆心 l为半径做了个圆 这样弧的总长就是2*PI*l 那剩下的就是直线 平移下来其实就是凸包的周长
然后卷包裹法或者扫描法都能过 毕竟数据弱
代码如下:
//卷包裹法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define PI 3.141592653589793
using namespace std;
typedef struct Point
{
int x,y;
double operator - (const struct Point a)const
{
return sqrt((x-a.x)*(x-a.x) + (y-a.y)*(y-a.y));
}
}Point;
typedef struct Line
{
int x,y;
bool operator > (const struct Line a)const//顺时针
{
return x*a.y - y*a.x > 0;
}
bool operator < (const struct Line a)const//逆时针
{
return x*a.y - y*a.x < 0;
}
}Line;
Point pt[1000];
int main()
{
int n,l,i;
double len;
int mp,tmp,mx;
mp = 0;
scanf("%d %d",&n,&l);
for(i = 0; i < n; ++i)//输入 同时找到最左最下
{
scanf("%d %d",&pt[i].x,&pt[i].y);
if(pt[i].x < pt[mp].x || (pt[i].x == pt[mp].x && pt[i].y < pt[mp].y))
mp = i;
}
len = 2*PI*l;
Line l1,l2;
tmp = mp;//以最左最下的点为起点
do//枚举每一个点 直到枚举完
{
mx = !tmp;
for(i = 0; i < n; ++i)
{
l1.x = pt[mx].x - pt[tmp].x;
l1.y = pt[mx].y - pt[tmp].y;
l2.x = pt[i].x - pt[tmp].x;
l2.y = pt[i].y - pt[tmp].y;
if(l2 > l1 || (!(l2 < l1) && pt[i]-pt[tmp] > pt[mx]-pt[tmp]))//找出极角最大并且距离前一点最远的点
mx = i;
}
len += pt[mx]-pt[tmp];//每找出一个凸包上的点就加一条边
tmp = mx;
}while(tmp != mp);//找回原点时凸包就建好了
printf("%.0f\n",len);
return 0;
}
//扫描法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <stack>
#include <algorithm>
#define PI 3.141592653589793
using namespace std;
int xx,yy;
typedef struct Point
{
int x,y;
double operator - (const struct Point a)const
{
return sqrt((x-a.x)*(x-a.x) *1.0+ (y-a.y)*(y-a.y)*1.0);
}
bool operator < (const struct Point a)const
{
if(x == xx && y == yy) return false;
if (a.x == xx && a.y == yy) return true;
if((x-xx)*(a.y-yy) - (y-yy)*(a.x-xx) == 0) return sqrt((x-xx)*(x-xx) *1.0+ (y-yy)*(y-yy)*1.0) < sqrt((a.x-xx)*(a.x-xx) *1.0+ (a.y-yy)*(a.y-yy)*1.0);
return (x-xx)*(a.y-yy) - (y-yy)*(a.x-xx) > 0;
}
}Point;
typedef struct Line
{
int x,y;
bool operator < (const struct Line a)const//逆时针
{
return x*a.y - y*a.x < 0;
}
}Line;
Point pt[1000];
stack <Point> s;
void SetTb(int n)//建凸包
{
Line l1,l2;
Point p1,p2;
s.push(Point{xx,yy});
s.push(pt[0]);
for(int i = 1; i < n; ++i)
{
p1 = s.top();
s.pop();
while(!s.empty())
{
p2 = s.top();
s.pop();
l1.x = pt[i].x - p2.x;
l1.y = pt[i].y - p2.y;
l2.x = p1.x - p2.x;
l2.y = p1.y-p2.y;
if(l1 < l2)
{
s.push(p2);
break;
}
p1 = p2;
}
s.push(p1);
s.push(pt[i]);
}
}
double Getlen()//从栈中不断出栈求凸包周长
{
Point p1,p2;
double len = 0;
p2 = s.top();
s.pop();
while(!s.empty())
{
p1 = s.top();
s.pop();
len += p2-p1;
p2 = p1;
}
return len;
}
void Read(int &n,int &l)//输入并进行极角排序
{
int mp = 0;
scanf("%d %d",&n,&l);
for(int i = 0; i < n; ++i)
{
scanf("%d %d",&pt[i].x,&pt[i].y);
if(pt[i].x < pt[mp].x || (pt[i].x == pt[mp].x && pt[i].y < pt[mp].y))
mp = i;
}
xx = pt[mp].x,yy = pt[mp].y;
}
int main()
{
int n,l,i;
double len;
Read(n,l);
len = 2*PI*l;
sort(pt,pt+n);
SetTb(n);
len += Getlen();
printf("%.0f\n",len);
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/challengerrumble/article/details/48029511