洛谷 P5544 [JSOI2016]炸弹攻击1 模拟退火

https://www.luogu.com.cn/problem/P5544

这题模拟退火模板题,从求最小值变成了求最大值,题解都是把接受差解的概率去掉?我吐了

之后看看求最大值有没有什么接受差解的题解,代码先放博客上。。。

#include<bits/stdc++.h>
using namespace std;

const int maxl=1e3+10;
const int rndmx=100000;
const double eps=1e-15;

mt19937 rnd(time(0));
uniform_int_distribution<> dis(1,rndmx);

int n,m,ans;
double sx,sy,R,mxx,mxy,mix,miy;
struct node
{
	double x,y,r;
}a[maxl],b[maxl];

inline void prework()
{
	scanf("%d%d%lf",&n,&m,&R);
	for(int i=1;i<=n;i++)
		scanf("%lf%lf%lf",&a[i].x,&a[i].y,&a[i].r);
	sx=0;sy=0;
	for(int i=1;i<=m;i++)
	{
		scanf("%lf%lf",&b[i].x,&b[i].y);
		sx+=b[i].x;sy+=b[i].y;
	}
	sx/=m;sy/=m;mix=mxx=sx;miy=mxy=sy;
	for(int i=1;i<=m;i++)
	{
		mix=min(b[i].x,mix),mxx=max(b[i].x,mxx);
		miy=min(b[i].y,miy);mxy=max(b[i].y,mxy);
	}
}

inline double dist(double x1,double y1,double x2,double y2)
{
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
} 

inline int calc(double x,double y)
{
	double r=R;
	for(int i=1;i<=n;i++)
		r=min(r,dist(x,y,a[i].x,a[i].y)-a[i].r);
	if(r<eps) return 0;
	int cnt=0;
	for(int i=1;i<=m;i++)
	if(dist(x,y,b[i].x,b[i].y)<r+eps)
		++cnt;
	return cnt;
}

inline void anneal()
{
	double t=30000,x=sx,y=sy,nx,ny;
	int now=calc(x,y),tmp,f;
	ans=max(now,ans);
	while(t>eps)
	{
		nx=x+(dis(rnd)*2-rndmx)*t;
		//nx=((rand()<<1)-RAND_MAX)*t;
		if(nx>mxx) nx=mxx;if(nx<mix) nx=mix; 
		ny=y+(dis(rnd)*2-rndmx)*t;
		//ny=y+((rand()<<1)-RAND_MAX)*t;
		if(ny>mxy) ny=mxy;if(ny<miy) ny=miy;
		tmp=calc(nx,ny);
		if(tmp>now)
		{
			now=tmp;ans=max(ans,tmp);
			x=nx;y=ny;
		}
		else if(exp(-(now-tmp))/t>1.0*dis(rnd)/100000)
		t*=0.9976;
	}
}

inline void mainwork()
{
	ans=0;
	//while((double)clock()/CLOCKS_PER_SEC<=0.6)
		anneal();
}

inline void print()
{
	printf("%d",ans);
}

int main()
{
	prework();
	mainwork();
	print();
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值