Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 5632 | Accepted: 1729 |
Description
Input
Output
Sample Input
3 1000 50 1 10 10 100 100 4 10 10 10 90 90 10 90 90 3000 3000 4 1200 85 63 2500 2700 2650 2990 100
Sample Output
The safest point is (1000.0, 50.0). The safest point is (50.0, 50.0). The safest point is (1433.0, 1669.8).
Source
题解:
昨天在网上浏览博客,无意看见有个ACMer交了这题并注明模拟淬火算法,由于在人工智能课上老师提到过这类演化算法-模拟淬火算法。感慨ACM在线OJ还能用模拟淬火算法这类概率算法,于是眼前一亮,有登上好久没有刷题的POJ了,看了道题。
题意是要求到给定n个点的最小距离最大的点,且点限定在给定矩形内。要是一维的,直接三分找极值即可;在平面上就不太好处理了。且这样的点可能不只一个,到底取谁都要考虑。前人提供了模拟淬火算法,直接搞定了。大致步骤如下:
1、随机选取一个合适的控制条件T作为开始
2、随机选取P个起始点,作为可行解
3、分别依据内能更新这P个可行解
4、减小控制条件T,直到终止条件
下面是代码:
#include<iostream> #include<cmath> #include<ctime> #include<cstdio> using namespace std; const int MAXN=1000+100; const int KMEAN=30; const double INF=1<<30; const double eps=1e-8; const double PI=3.141592653; int x,y,n; struct Point { double x,y; }myPoint[MAXN],myK[KMEAN]; double dis[KMEAN]; double GetMinDis(double tx,double ty) { double minDis=INF,temp; for(int i=0;i<n;i++) { temp=sqrt((tx-myPoint[i].x)*(tx-myPoint[i].x)+(ty-myPoint[i].y)*(ty-myPoint[i].y)); if(temp<minDis) minDis=temp; } return minDis; } int main() { int cas,i,j; double temp; scanf("%d",&cas); while(cas--) { scanf("%d%d%d",&x,&y,&n); srand((unsigned)time(NULL)); for(i=0;i<n;i++) scanf("%lf%lf",&myPoint[i].x,&myPoint[i].y); for(i=0;i<KMEAN;i++) { dis[i]=INF; myK[i].x=rand()%10001/10000.0*x; myK[i].y=rand()%10001/10000.0*y; } for(i=0;i<KMEAN;i++) dis[i]=GetMinDis(myK[i].x,myK[i].y); double theta,delta=1.0*(x>y?x:y)/sqrt(1.0*n); while(delta>eps) { for(i=0;i<KMEAN;i++) { double nx=myK[i].x,ny=myK[i].y; for(j=0;j<KMEAN;j++) { double tx,ty; theta=double(rand()%10001)/10000.0*2*PI; tx=nx+delta*cos(theta); ty=ny+delta*sin(theta); if(tx<0||tx>x||ty<0||ty>y) continue; temp=GetMinDis(tx,ty); if(temp>dis[i]) { myK[i].x=tx; myK[i].y=ty; dis[i]=temp; } } } delta=0.8*delta; } int id=-1; temp=-INF; for(i=0;i<KMEAN;i++) { if(dis[i]>temp) { temp=dis[i]; id=i; } } printf("The safest point is (%.1lf, %.1lf).\n",myK[id].x,myK[id].y); } return 0; }
下面是相似的题
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 3274 | Accepted: 1666 |
Description
Input
Output
Sample Input
4 0 0 0 10000 10000 10000 10000 0
Sample Output
28284
题解:
本题与上面那题的唯一区别就是目的函数不同,此处为最短距离和,上面为最短距离的最大者,模拟淬火算法。直接贴代码的。
#include<iostream> #include<cmath> #include<ctime> #include<cstdio> using namespace std; const int MAXN=100+10; const int KMEAN=30; const double INF=1<<30; const double eps=1e-8; const double PI=3.141592653; double x=10000.0,y=10000.0; int n; struct Point { double x,y; }myPoint[MAXN],myK[KMEAN]; double dis[KMEAN]; double GetMinDis(double tx,double ty) { double temp=0; for(int i=0;i<n;i++) { temp+=sqrt((tx-myPoint[i].x)*(tx-myPoint[i].x)+(ty-myPoint[i].y)*(ty-myPoint[i].y)); } return temp; } int main() { int i,j; double temp; while(scanf("%d",&n)!=EOF) { srand((unsigned)time(NULL)); for(i=0;i<n;i++) scanf("%lf%lf",&myPoint[i].x,&myPoint[i].y); for(i=0;i<KMEAN;i++) { dis[i]=INF; myK[i].x=rand()%10001/10000.0*x; myK[i].y=rand()%10001/10000.0*y; } for(i=0;i<KMEAN;i++) dis[i]=GetMinDis(myK[i].x,myK[i].y); double theta,delta=10000.0/sqrt(1.0*n); while(delta>eps) { for(i=0;i<KMEAN;i++) { double nx=myK[i].x,ny=myK[i].y; for(j=0;j<KMEAN;j++) { double tx,ty; theta=double(rand()%10001)/10000.0*2*PI; tx=nx+delta*cos(theta);//可改变方向 ty=ny+delta*sin(theta); temp=GetMinDis(tx,ty); if(temp<dis[i]) { myK[i].x=tx; myK[i].y=ty; dis[i]=temp; } } } delta=0.98*delta; } temp=INF; for(i=0;i<KMEAN;i++) { if(dis[i]<temp) { temp=dis[i]; } } printf("%.0lf\n",temp); } return 0; }
下面这题是求最小圆覆盖。
Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1397 Accepted Submission(s): 625
1000 50 1 10 10 1000 50 4 0 0 1 0 0 1 1 1
(10.0,10.0). 0.0 (0.5,0.5). 0.7
题解:
题意是要求到给定n个点的最大距离最小的点,且点限定在给定矩形内,对应数学模型最小点覆盖。贴段代码:
#include<iostream> #include<cmath> #include<ctime> #include<cstdio> using namespace std; const int MAXN=1000+100; const int KMEAN=30; const double INF=1<<30; const double eps=1e-8; const double PI=3.141592653; int x,y,n; struct Point { double x,y; }myPoint[MAXN],myK[KMEAN]; double dis[KMEAN]; double GetMaxDis(double tx,double ty) { double maxDis=-INF,temp; for(int i=0;i<n;i++) { temp=sqrt((tx-myPoint[i].x)*(tx-myPoint[i].x)+(ty-myPoint[i].y)*(ty-myPoint[i].y)); if(temp>maxDis) maxDis=temp; } return maxDis; } int main() { int i,j; double temp; while(scanf("%d%d%d",&x,&y,&n)!=EOF) { srand((unsigned)time(NULL)); for(i=0;i<n;i++) scanf("%lf%lf",&myPoint[i].x,&myPoint[i].y); for(i=0;i<KMEAN;i++) { dis[i]=INF; myK[i].x=rand()%10001/10000.0*x; myK[i].y=rand()%10001/10000.0*y; } for(i=0;i<KMEAN;i++) dis[i]=GetMaxDis(myK[i].x,myK[i].y); double theta,delta=1.0*(x>y?x:y)/sqrt(1.0*n); while(delta>eps) { for(i=0;i<KMEAN;i++) { double nx=myK[i].x,ny=myK[i].y; for(j=0;j<KMEAN;j++) { double tx,ty; theta=double(rand()%10001)/10000.0*2*PI; tx=nx+delta*cos(theta); ty=ny+delta*sin(theta); if(tx<0||tx>x||ty<0||ty>y) continue; temp=GetMaxDis(tx,ty); if(temp<dis[i]) { myK[i].x=tx; myK[i].y=ty; dis[i]=temp; } } } delta=0.8*delta; } int id=-1; temp=INF; for(i=0;i<KMEAN;i++) { if(dis[i]<temp) { temp=dis[i]; id=i; } } printf("(%.1lf,%.1lf).\n%.1lf\n",myK[id].x,myK[id].y,temp); } return 0; }