P5544 [JSOI2016]炸弹攻击1 【模拟退火】
洛谷 P5544 -> Click Here
题意
平面上有一些建筑和敌人,建筑为一个圆,敌人为一个点,让我们圈起来一个圆形,问最多有几个敌人在这个圆中,且圆与建筑圆没有重合部分,若敌人在所圈起来的圆的圆弧上则也算在圆中(详情请查看原题链接
思路
经典平面上求最大值问题,设初始时选择的圆心为所有敌人所组成的形状的重心(随便选一个也可以,为所谓),进行模拟退火,随机产生新的点,查看新点所能包括的敌人是否更优,随着的温度的降低,随机生成的点从离谱变得有谱起来,以接近最优解,多重复几次增大找到正解的几率
code
#include<iostream>
#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define REP(i,a,b) for(int i=(a);i<=(b);i++)
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define down 0.996
#define eps 1e-15
#define N 15
#define M 1005
using namespace std;
struct build{double x,y,r;}s[N];
double a[M],b[M],sumx,sumy,ansx,ansy,R,n,m,ans;
double dis(double x,double y,double xx,double yy){
return sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy));
}
double Query(double x,double y){
double res=0,d=R;
REP(i,1,n) d=min(d,dis(x,y,s[i].x,s[i].y)-s[i].r);
REP(i,1,m) if(dis(x,y,a[i],b[i])<=d) res++;
return res;
}
void SA(){
double T=3000;
double nowx=ansx;
double nowy=ansy;
while(T>eps){
double xx=nowx+((rand()<<1)-RAND_MAX)*T;
double yy=nowy+((rand()<<1)-RAND_MAX)*T;
double nowans=Query(xx,yy);
double del=nowans-ans;
if(del>0){
ansx=xx;
ansy=yy;
nowx=xx;
nowy=yy;
ans=nowans;
}else if(exp(- del/T)*RAND_MAX<rand()){
nowx=xx;
nowy=yy;
}
T*=down;
}
}
int main(){
srand(1e9+7);
scanf("%lf%lf%lf",&n,&m,&R);
REP(i,1,n) scanf("%lf%lf%lf",&s[i].x,&s[i].y,&s[i].r);
REP(i,1,m){
scanf("%lf%lf",&a[i],&b[i]);
sumx+=a[i];
sumy+=b[i];
}
ansx=sumx/m;
ansy=sumy/m;
while((double)clock()/CLOCKS_PER_SEC<=0.8) SA();
printf("%.0lf\n",ans);
return 0;
}

浙公网安备 33010602011771号