POJ 2420
模拟退火算法。昨天看了PPT,原来模拟退火算法涉及到马尔什么链,开始理解,它其实就是一个关于抽样的问题。随机抽样,选取足够多的样本,然后逐步逼近。而在平面上,由于T的下降,使得逐渐缩小至一点。然后,就可以了。
算法:
在平面上随机选取一些点,当然这些点应当有一点相关的性吧。我猜的。
然后在这些点随机移动,若移动后更优,则移动,否则,留待下一次循环。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <time.h> using namespace std; const int MAXN=110; const int MAX=50; struct point { double x,y; }; point p[MAXN]; int n; point s,tt; double ans_dis,tmp_dis; point tar[MAX]; double getdouble(){ double ret=(rand()*rand()%10000)*1.0/1e5; if(rand()&1) ret*=-1; return ret; } double dist(point &u,point &v){ return sqrt((u.x-v.x)*(u.x-v.x)+(u.y-v.y)*(u.y-v.y)); } double work(point &s){ double ret=0; for(int i=0;i<n;i++){ ret+=dist(p[i],s); } return ret; } int main(){ srand(time(0)); while(scanf("%d",&n)!=EOF){ s.x=s.y=0; ans_dis=tmp_dis=0; for(int i=0;i<n;i++){ scanf("%lf%lf",&p[i].x,&p[i].y); s.x+=p[i].x; s.y+=p[i].y; } s.x/=n; s.y/=n; for(int i=0;i<MAX;i++){ tar[i].x=s.x+getdouble()*100; tar[i].y=s.y+getdouble()*100; } double T=100; double ans_dis=work(s); for(double t=T; t>1e-8;t*=0.8){ for(int i=0;i<MAX;i++){ double tmp_dis=work(tar[i]); for(int j=0;j<10;j++){ tt.x=tar[i].x+getdouble()*t; tt.y=tar[i].y+getdouble()*t; double f=work(tt); if(f<tmp_dis) tar[i]=tt; } } } for(int i=0;i<MAX;i++){ double mm=work(tar[i]); ans_dis=min(ans_dis,mm); } printf("%.0lf\n",ans_dis); } return 0; }