记录编号 213251 评测结果 AAAAAAAA
题目名称 [CEOI1999][POJ1379]逃离陷阱 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 0.823 s
提交时间 2015-12-11 11:53:08 内存使用 0.36 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<cmath>
using namespace std;
#define sqr(x) (x)*(x)
const int SIZEN=1010;
const double INF=1e10,pi=acos(-1.0),eps=1e-7;
class POINT{
public:
	double x,y;
	double d;
};
int random(int x,int y){
	return rand()%(y-x+1)+x;
}
double random_real(void){//生成一个[0,1]内的实数
	return ((((rand()<<15)|rand())&0x3fffffff)+0.0)/(0x3fffffff+0.0);
}
double W,H;
int N;
POINT hole[SIZEN];
POINT P[SIZEN];
double dist(POINT a,POINT b){
	return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}
double calc(POINT a){
	if(a.x<0||a.x>W||a.y<0||a.y>H) return -INF;
	double ans=INF;
	for(int i=1;i<=N;i++) ans=min(ans,dist(a,hole[i]));
	return ans;
}
void jump(POINT &a,double r,double T){//点为a,步长为r,温度为T
	double alpha=random(0,359)/180.0*pi;
	POINT b;//在以a为圆心,r为半径的圆上随机一个点b
	b.x=a.x+r*cos(alpha),b.y=a.y+r*sin(alpha);
	if(b.x<0||b.x>W||b.y<0||b.y>H) return;//如果b不合法 
	b.d=calc(b);
	if(b.d>a.d) a=b;//如果比当前解优,直接接受 
	else{//否则以概率e^(-△/T)接受这个解
		double p=exp(-(a.d-b.d)/T);
		if(random_real()<=p) a=b;
	}
}
void SA(void){
	int n=20;//点的数量
	/*模拟退火算法具有并行性,可以从一组初始点开始同时运行,
	使最终的解更优*/
	double T=1000.0;//初始温度
	double delta=max(W,H)/sqrt(n+0.0);//初始步长
	int rep=30;//同一温度迭代30次
	for(int i=1;i<=n;i++){//初始点均由随机生成 
		P[i].x=random(0,W);
		P[i].y=random(0,H);
		P[i].d=calc(P[i]);
	}
	while(delta>eps){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=rep;j++) jump(P[i],delta,T);
		}
		delta*=0.9,T*=0.8;
	}
	int ans=1;
	for(int i=2;i<=n;i++) if(P[i].d>P[ans].d) ans=i;
	printf("The safest point is (%.1lf, %.1lf).\n",P[ans].x,P[ans].y);
}
void read(void){
	scanf("%lf%lf%d",&W,&H,&N);
	for(int i=1;i<=N;i++) scanf("%lf%lf",&hole[i].x,&hole[i].y);
}
int main(){
	freopen("runaway.in","r",stdin);
	freopen("runaway.out","w",stdout);
	srand(time(0));
	int T;//原题是ACM赛制,有多组数据 
	//scanf("%d",&T);
	T=1;
	while(T--){
		read();
		SA();
	}
	return 0;
}