给出平面上N(<=100)个点,你需要找到一个这样的点,使得这个点到N个点的距离之和尽可能小。输出这个最小的距离和(四舍五入到最近的整数)。
Input
第一行N,接下来N行每行两个整数,表示N个点
Output
一行一个正整数,最小的距离和。
Sample Input
4 0 0 0 10000 10000 10000 10000 0
Sample Output
28284
思路:
模拟退火,注意四舍五入,用double 输出需要用%f,longlong输出需要round()。
三分套三分,确定x后,y是一个二次函数,可以用三分套三分求解。
模拟退火:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
#include<bitset>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const double eps=1e-10;
int n;
struct node{int x,y;void input(){scanf("%d%d",&x,&y);}
}a[maxn];
double dis(double x,double y,double x1,double y1){return sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1));
}
double alldis(double x,double y){double res=0;for(int i=0;i<n;i++){res+=dis(x,y,a[i].x,a[i].y);}return res;
}
double solve(double x,double y){double T=100000;while(T>eps){double tx=x+(rand()*2-RAND_MAX)*T;double ty=y+(rand()*2-RAND_MAX)*T;double delta=alldis(tx,ty)-alldis(x,y);if(delta<0){x=tx;y=ty;}else if(exp(-delta/T)*RAND_MAX>rand()){x=tx;y=ty;}T*=0.99;}return alldis(x,y);
}
int main(){cin>>n;for(int i=0;i<n;i++) a[i].input();printf("%.0f\n",solve(0,0));return 0;
}
三分套三分:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
#include<bitset>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const double eps=1e-10;
int n;
struct node{int x,y;void input(){scanf("%d%d",&x,&y);}
}a[maxn];
double dis(double x,double y,double x1,double y1){return sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1));
}
double alldis(double x,double y){double res=0;for(int i=0;i<n;i++){res+=dis(x,y,a[i].x,a[i].y);}return res;
}double check(double x){double l=0,r=10000;double ans=0;while((r-l)>eps){double m1=l+(r-l)/3;double m2=r-(r-l)/3;double ans1=alldis(x,m1);double ans2=alldis(x,m2);if(ans1<ans2) r=m2,ans=ans1;else l=m1,ans=ans2;}return ans;
}
int main(){cin>>n;for(int i=0;i<n;i++) a[i].input();double l=0,r=10000;double ans=0;while((r-l)>eps){double m1=l+(r-l)/3;double m2=r-(r-l)/3;double ans1=check(m1);double ans2=check(m2);if(ans1<ans2) r=m2,ans=ans1;else l=m1,ans=ans2;}printf("%.0f\n",ans);return 0;
}