[bzoj4852][Jsoi2016]炸弹攻击【随机化】
【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=4852
【题解】
在平面中随机选取一些点作为初始点,然后模拟退火。
tip:在模拟退火时,由于答案比较小,但是温度比较高,所以在算时最好把相差的点数乘以一个常数让选取更差的的概率降低。
/* --------------
user Vanisher
problem bzoj-4852
----------------*/
# include <bits/stdc++.h>
# define ll long long
# define inf 0x3f3f3f3f
# define N 11
# define M 1010
using namespace std;
int read(){
int tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
struct Point{
double x,y;
}p[M];
Point operator +(Point x, Point y){return (Point){x.x+y.x,x.y+y.y};}
struct Circle{
Point p;
double r;
}b[N];
int n,m,ans;
double mr;
double sqr(double x){return x*x;}
double dis(Point x, Point y){
return sqrt(sqr(x.x-y.x)+sqr(x.y-y.y));
}
double rand_0_1(){return (rand() % 32767) / 32767.0;}
double solve(Point x){
double r=mr; double cnt=0;
for (int i=1; i<=n; i++)
r=min(r,dis(b[i].p,x)-b[i].r);
if (r<0) return 0;
for (int i=1; i<=m; i++)
if (dis(x,p[i])<=r) cnt++;
return cnt;
}
int Simulate_Anneal(Point ths, double S, double P, double Lim){
double mx=solve(ths), now=mx, tmp;
Point nex;
for (double t=S; t>=Lim; t=t*P){
double step = t * mr / S + 0.1;
nex.x=ths.x+(2*step)*rand_0_1()-step;
nex.y=ths.y+(2*step)*rand_0_1()-step;
tmp=solve(nex);
if (tmp>now) ths=nex, now=tmp;
else if (exp(1e4*(tmp-now)/t)>rand_0_1())
ths=nex, now=tmp;
mx=max(now,mx);
}
return mx;
}
int main(){
n=read(), m=read(), mr=read();
for (int i=1; i<=n; i++)
b[i].p.x=read(), b[i].p.y=read(), b[i].r=read();
for (int i=1; i<=m; i++)
p[i].x=read(), p[i].y=read();
for (int i=1; i<=20; i++)
ans=max(ans,Simulate_Anneal((Point){2*mr*rand_0_1()-mr,2*mr*rand_0_1()-mr},mr,0.998,0.01));
printf("%d\n",ans);
return 0;
}