题解 P5544 【[JSOI2016]炸弹攻击1】
infinities · · 题解
练习模拟退火的好题。
模拟退火板子学习可以自己左转BFS(Baidu-First-Search)。
按照套路,我们先随便选一组开始的答案坐标,然后模拟退火不断更新即可。
算当前答案,我们既然已经确定了炸弹的中心点,那么肯定会贪心一下,使得当前炸弹的波及范围半径尽可能大(在不误伤建筑和不超过和题目中的限制
算这个最大半径只需要枚举每一个建筑,算出建筑中心点和当前点的距离,然后再用这个距离减去建筑的半径
然后枚举每一个敌人,看能攻击到多少即可。
注:这题求的是最大值,所以我们不一定接受的答案所对应的(当前答案减去上一次答案)
if(exp(-del / ts) > (double)rand() / RAND_MAX)ansx = sumx, ansy = sumy, ans1 = ansnow;
改成
if(exp(-del / ts) < (double)rand() / RAND_MAX)ansx = sumx, ansy = sumy, ans1 = ansnow;
就完事了。
还有就是把坐标,距离等等都要开成double,尽量多跑几遍模拟退火加大得出最优解的概率。
code:
#include<bits/stdc++.h>
#define ll long long
#define rint register int
const int maxn = 5e5;
const int INF = 2e9;
int read(){
int x = 0,f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if(ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
using namespace std;
int n, m, r, xb[maxn], yb[maxn], rb[maxn], xe[maxn], ye[maxn], ans;
double delta = 0.996, te = 1e-10;
double ansx, ansy;
void init(){
ansx = 0, ansy = 0;
n = read(), m = read(), r = read();
for(int i = 1; i <= n; i++){xb[i] = read(); yb[i] = read(); rb[i] = read();}
for(int i = 1; i <= m; i++){xe[i] = read(); ye[i] = read(); ansx += xe[i]; ansy += ye[i];}
ansx /= m, ansy /= m;
}
double loca(double x1, double y1, double x2, double y2){
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
int check(double x, double y){
int anss = 0;
double r_ = (double)r;
for(int i = 1; i <= n; i++){
r_ = min(r_, loca(x, y, xb[i], yb[i]) - (double)rb[i]);
}
for(int i = 1; i <= m; i++){
if(loca(x, y, xe[i], ye[i]) <= r_)anss++;
}
return anss;
}
void SA(){
double ts = 11451.4;
int ans1 = 0;
while(ts > te){
double sumx = ansx + ((rand() << 1) - RAND_MAX) * ts;
double sumy = ansy + ((rand() << 1) - RAND_MAX) * ts;
int ansnow = check(sumx, sumy);
int del = ansnow - ans1;
if(del > 0)ansx = sumx, ansy = sumy, ans1 = ansnow, ans = max(ansnow, ans);
else if(exp(-del / ts) < (double)rand() / RAND_MAX)ansx = sumx, ansy = sumy, ans1 = ansnow;
ts = ts * delta;
}
}
void solve(){
srand(time(0));
init();
SA();
SA();
SA();
SA();
SA();
SA();//多跑几遍
cout << ans;
return;
}
signed main(){
solve();
}