(一)题面:
Description
In this situation, LEN (P 1, P 2, ..., P N) is a function of P 1, P 2, ..., P N. When P 1, P 2, ..., P N change their positions, LEN (P 1, P 2, ..., P N) also changes. It's easy to prove that there exist some P 1', P 2', ..., P N' in the square such that LEN (P 1', P 2', ..., P N') is at its minimum.
Given the initial positions of N points, your task is to find out N points P 1", P 2", ..., P N" in the square such that |P 1P 1"| + |P 2P 2"| + ... + |P NP N"| is minimum and LEN (P 1", P 2", ..., P N") = LEN (P 1', P 2', ..., P N') . You are requested to output the value of |P 1P 1"| + |P 2P 2"| + ... + |P NP N"|, where |PiPi"| is the distance between Pi and Pi".

For example, Figure-1 gives the initial position of P 1 and the way of connecting to obtain LEN (P 1). In Figure-2, it gives the position of P 1", which is at the center of the square, and the way of connecting to obtain LEN (P 1"). It can be proved that LEN (P 1") = LEN (P 1’); your job is to output the distance between P 1 and P 1".
Input
x y
Here, x and y are float numbers within the value [0, 1].
A test case of N = 0 indicates the end of input, and should not be processed.
Output
Sample Input
1 0.2 0.5 2 0 0.5 0.5 0.5 0
Sample Output
0.300 0.500
(二)题目大意:
在一个正方形中给出n个点S,让你找到另外n个点S',使得正方形的四个顶点以及S'中所有点相连的线段总的长度和最小,且使得S中的点到S'中的对应点的距离之和最小(可能直接看题目更清楚QWQ)。
(三)解题思路:
①考虑一个点,那么找的点就是正方形的中心,然后求一下和原来给出的点的距离即可。
②考虑两个点,如果两个点不重合,根据对称性思维,则找的两个点大致上如下图一位置:
③再想具体再哪一个位置。将正方形分成左右两个部分,那么我们可以得到两个三角形(图二中红色三角形),接下来不难想到找的两个点应该分别是两个三角形的费马点。同理我们将矩形分成上下两个部分可以得到图三的两个点。计算后可得总的长度为1+sqrt(3),比在中心时的距离2*sqrt(2)要小。说明两个点的时候,上图最优。
④对于更多的点呢,这里只有一个猜想:当n>2时,最小距离和也由上图得到。那么接下来就是先在给出的n个点中找最优的两个点放到图中的两个点的位置,其余的n-2个点就映射到五条线段上的最近的位置即可(分为图二和图三两种情况,取最小值)。
⑤费马的点的定义及求解具体百度~(注意这里的两个三角形是等腰直角三角形)。
(四)具体代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define esp 1e-6
using namespace std;
int n;
struct Point{
double x,y;
Point(){}
Point(double _x,double _y){x=_x;y=_y;}
Point operator - (const Point& b)const{
return Point(x-b.x,y-b.y);
}
double operator * (const Point& b)const{
return x*b.x+y*b.y;
}
}p[110];
struct Line{
Point s,e;
Line(Point p1,Point p2){
s=p1,e=p2;
}
};
double best=1e9;
const Point only(0.5,0.5);
const Point one(sqrt(3.0)/6.0,0.5);
const Point two(1.0-sqrt(3.0)/6.0,0.5);
const Point three(0.5,sqrt(3.0)/6.0);
const Point four(0.5,1.0-sqrt(3.0)/6.0);
const Point lu(0,1),ld(0,0),ru(1,1),rd(1,0);
const Line Line1(one,two),Line2(lu,one),Line3(ru,two),Line4(ld,one),Line5(rd,two);
const Line Line6(three,four),Line7(rd,three),Line8(lu,four),Line9(ld,three),Line10(ru,four);
Line line1[5]={Line1,Line2,Line3,Line4,Line5};
Line line2[5]={Line6,Line7,Line8,Line9,Line10};
double dist(Point n1,Point n2){
return sqrt((n1.x-n2.x)*(n1.x-n2.x)+(n1.y-n2.y)*(n1.y-n2.y));
}
double Get_nearest_point(Point P,Line L){
Point result;
double t=((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s));
if(t>=0.0&&t<=1.0){
result.x=L.s.x+(L.e.x-L.s.x)*t;
result.y=L.s.y+(L.e.y-L.s.y)*t;
}
else{
if(dist(P,L.s)-dist(P,L.e)<esp)result=L.s;
else result=L.e;
}
return dist(result,P);
}
double Get_dist_to_line(int x,Line l[5]){
double _Min=1e9;
for(int i=0;i<5;i++)
_Min=min(_Min,Get_nearest_point(p[x],l[i]));
return _Min;
}
double solve(Line l[5],Point p1,Point p2){
int pos1,pos2;
double ans=0,_Min=1e9;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(i==j)continue;
double d1=dist(p[i],p1),d2=dist(p[j],p2);
double d3=Get_dist_to_line(i,l),d4=Get_dist_to_line(j,l);
if(_Min>d1-d3+d2-d4){_Min=d1-d3+d2-d4;pos1=i;pos2=j;}
}
}
ans=dist(p[pos1],p1)+dist(p[pos2],p2);
for(int i=0;i<n;i++){
if(i==pos1||i==pos2)continue;
ans+=Get_dist_to_line(i,l);
}
return ans;
}
int main(){
freopen("in.txt","r",stdin);
while(~scanf("%d",&n)&&n){best=1e9;
for(int i=0;i<n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);
if(n==1){printf("%.3lf\n",dist(p[0],only));continue;}
printf("%.3lf\n",min(solve(line1,one,two),solve(line2,three,four))+esp);
}
return 0;
}
(五)总结:
其实这个题和费马点的关系并不是特别大了...。总之,敢猜敢想,说不定就猜对了呢23333。