NOJ[1362]—— 最短路线

  • 问题描述
  • 从前有座山,山里有个城堡,城堡三面环山。城主为了防御敌人的入侵,所以在大道横向筑起了一道墙,这样一来就是个铜墙铁壁了,易守难攻。该墙是直线型的,没有弯曲的部分。但是,一旦有人入侵,军队应该快速赶到城墙防御敌人。所以,城主在城墙内又筑起一些军营。现在告诉你这些军营的坐标,那么如何建造城墙(你可以考虑城墙是无限延伸的),才能使所有军营到城墙的距离之和最短?


  • 输入
  • 输入第一行包括一个正整数 N(4 <= N <= 10000),表示为军营的数量。
    接下来N行,每行包括两个实数 x(-1000.00 <= x <= 1000.00)和 y(-1000.00 <= y <= 1000.00),表示该军营的坐标(不会有两个军营在同一坐标上,且不会所有的点都在一直线上;军营在城墙上也是可以的)。
  • 输出
  • 输出一行为所有军营到城墙的距离之和的最小值,保留两位小数。
  • 样例输入
  • 4
    0.00 0.00
    1.00 1.00
    0.00 1.00
    1.00 0.00
  • 样例输出
  • 2.00
  • 提示
  • Use scanf and printf instead of cin and cout. 
  • 来源
  • Hungar
    思考,所有点一定是在城墙的一侧的,而且点可以在城墙上,那么我们一定是选最外侧的点连成的线做城墙,所以要先求出这些点的凸包,那么城墙一定是凸包的某条边。
   接下来,就是求出最短距离了,如果暴力的话,复杂度大概是O(N^2),而点又多达10000,最坏情况10000个点都是在凸包上的,那么有9999条边,一定会超时,所以要优化。
   我刚才说了,点是在线段的一侧的,那么,这些点到线段的有向距离一定是同号的
距离公式: |y-k*x+b|/ (1+k^2)

所以,绝对值符号可以脱去,那么最后就是 |∑y-k*∑x+n*b|/ (1+k^2),
所以我们要做的就是把所有点的横纵坐标的和求出来,然后枚举边,维护一个最小值即可。
注意本题用graham算法可能会超时,保险起见,还是用andrew算法。


#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>

using namespace std;

struct point
{
double x,y;
}list[10010];

int stack[10010];


double cross(point p0,point p1,point p2)
{
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
int cmp(point a,point b)
{
if(a.x == b.x)
return a.y < b.y;
return a.x < b.x;
}
int andrew(int n)
{
sort(list,list+n,cmp);
int top=1;
stack[0]=0;
stack[1]=1;
for(int i=2;i<n;i++)
{
while(top>0 && cross(list[stack[top-1]],list[stack[top]],list[i]) <=0 )
top--;
stack[++top]=i;
}
int k=top;
stack[++top]=n-2;
for(int i=n-3;i>=0;i--)
{
while(top>k && cross(list[stack[top-1]],list[stack[top]],list[i])<=0)
top--;
stack[++top]=i;
}
return top;
}

int main()
{
int n;
while(~scanf("%d",&n))
{
double x=0.00;
double y=0.00;
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&list[i].x,&list[i].y);
x+=list[i].x;
y+=list[i].y;
}
int top=andrew(n);
double mins=2100000000,k,b,temp;
for(int i=0;i<top;i++)
{
if(list[stack[i]].x == list[stack[(i+1)%top]].x)
temp=fabs(n*list[stack[i]].x - x);
else
{
k=(list[stack[i]].y - list[stack[(i+1)%top]].y)/(list[stack[i]].x - list[stack[(i+1)%top]].x);
b=list[stack[i]].y-list[stack[i]].x * k;
temp=fabs(k*x-y+b*n)/sqrt(k*k+1);
}
mins=min(mins,temp);
}
printf("%.2lf\n",mins);
}
return 0;
}



你可能感兴趣的:(NOJ[1362]—— 最短路线)