【POJ1379】Run Away 模拟退火

#include <stdio.h>
int main()
{
	puts("转载请注明出处[vmurder]谢谢");
	puts("网址:blog.csdn.net/vmurder/article/details/43526827");
}


题意:

给若干个点,现在求一个点,使它到离它最近的点尽量远。


题解:

我写的是模拟退火先玩一会,然后小幅度爬爬山。


种子的采用是20134858

是生日^人的名字首字母hash。


诶可算A了,看来我脸还不是太黑。


代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10100
#define dinf 1e18
#define eps 1e-5
#define down 0.998
using namespace std;
double n,m;
struct Point // 点
{
	double x,y,z; // 坐标、该点作为结束点的答案。
	Point(double _x=0.0,double _y=0.0):x(_x),y(_y){}
	bool in()
	{
		if(x<0.0||x>n)return 0;
		if(y<0.0||y>m)return 0;
		return 1;
	}
}P[N],now,ans;

int p;

// 随机函数,随机出来一个0~1之间的小数
inline double Rand(){return ((double)(rand()%1000+1.0))/1000.0;}

// 其实找初始点时最好找平均数之类
inline void init() 
{
	double tempx=0.0,tempy=0.0;
	for(int i=1;i<=p;i++)tempx+=P[i].x,tempy+=P[i].y;
		tempx+=2*n,tempy+=2*m;
	now=Point(tempx/(p+4),tempy/(p+4));
//	now=Point(n/2,m/2);
	ans.z=0.0;
}

// 计算两点间欧拉距离
inline double calc(const Point &a,const Point &b)
{return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}

// 计算所有点到点a的欧拉距离最小值并更新ans
inline double Calc(Point &a)
{
	a.z=dinf;
	for(int i=1;i<=p;i++)a.z=min(a.z,calc(P[i],a));
	if(a.z>ans.z)ans=a;
	return a.z;
}
Point newpos(double T,const Point &a)
{
	double alp=2.0*acos(-1.0)*Rand(); // 角度
	return Point(a.x+T*cos(alp)*Rand(),a.y+T*sin(alp)*Rand());
}
// 模拟退火
void Std_Anne() // [S]imula[t]e[d] [Anne]aling
{
	 //  温度,或者说转移半径
	for(double T=sqrt(n*n+m*m)*0.42;T>eps;T*=down) // 每次降温
	{
		Point next=newpos(T,now);
		// next为转移后的点
		if(next.in())
		{
			double dis=Calc(next)-Calc(now);
			if(exp(dis/T)>Rand()-eps)now=next;
		}
	}
}

// 爬山
void ioi()  // Cl[i]mb M[o]unta[i]n
{
	double T=0.5,alp;
	for(int i=1;i<=50000;i++)
	{
		Point next=newpos(T,ans);
		if(next.in())
		{
			double dis=Calc(next)-Calc(now);
			if(dis>0)now=next;
		}
	}
}

int main()
{
	freopen("test.in","r",stdin);
	srand(20134858);
	int i,j,k,g;
	for(scanf("%d",&g);g--;)
	{
		scanf("%lf%lf%d",&n,&m,&p);
		for(i=1;i<=p;i++)
			scanf("%lf%lf",&P[i].x,&P[i].y);
		init();
		Std_Anne();
		ioi();
		printf("The safest point is (%.1lf, %.1lf).\n",ans.x,ans.y);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值