题解:P5544 [JSOI2016] 炸弹攻击1
这题很明显是一道模拟退火,直接按照模板写出代码来:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 10 + 5;
const int M = 1e3 + 5;
const double down = 0.9985;
int n, m, R, ans;
struct peo{
double x, y;
}b[M];
struct bui{
double x, y, r;
}a[N];
int bst;
double tx, ty;
double dist(double x1, double y1, double x2, double y2) {
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
int energy(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);
}
int tot = 0;
for (int i = 1; i <= m; i++) {
if(dist(x, y, b[i].x, b[i].y) <= r) {
tot++;
}
}
return tot;
}
void SA() {
double t = 1e4;
while (t > 1e-10) {
double dx = tx + (rand() * 2 - RAND_MAX) * t;
double dy = ty + (rand() * 2 - RAND_MAX) * t;
int now = energy(dx, dy);
double delta = bst - now;
if (delta < 0) {
tx = dx;
ty = dy;
bst = now;
ans =max(ans, now);
}
else if (exp(delta / t) * RAND_MAX < rand()) {
tx = dx;
ty = dy;
bst = now;
}
t *= down;
}
}
signed main() {
srand(324531);
cin >> n >> m >> R;
for (int i = 1; i <= n; i++) {
cin >> a[i].x >> a[i].y >> a[i].r;
}
for (int i = 1; i <= m; i++) {
cin >> b[i].x >> b[i].y;
tx += b[i].x;
ty += b[i].y;
}
tx /= m;
ty /= m;
bst = energy(tx, ty);
while (((double)clock() / CLOCKS_PER_SEC) < 0.9)
SA();
cout << ans;
return 0;
}
如果这样子,你可以过掉这道题的原始数据,但是,由于用户 do_it_tomorrow 坚持不懈的 HACK,我们会 WA 在 #12 上。
我们开始乱搞:
首先,我们可以先以 $\left { \frac{\sum_{i=1}^{m} p_i}{m} ,\frac{\sum_{i=1}^{m} q_i}{m} \right } $ 为初始点位进行一次模拟退火,然后分别将每一个敌人设为初始点位进行一次模拟退火,这样会让答案越来越接近最优解。但是如果只这样做了话,会 TLE 一堆点,得不偿失。
我们随便动一下参数,再进行去重,然后让设置每一个敌人为初始点位进行一次模拟退火的概率为 \(\frac{3}{4}\)。这样就可以过 HACK 了。
AC 代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 10 + 5;
const int M = 1e3 + 5;
const double down = 0.999;
int n, m, R, ans;
struct peo{
double x, y;
}b[M];
struct bui{
double x, y, r;
}a[N];
int bst;
double tx, ty;
double dist(double x1, double y1, double x2, double y2) {
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
int energy(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);
}
int tot = 0;
for (int i = 1; i <= m; i++) {
if(dist(x, y, b[i].x, b[i].y) <= r) {
tot++;
}
}
return tot;
}
void SA() {
double t = 2000;
while (t > 1e-10) {
double dx = tx + (rand() * 2 - RAND_MAX) * t;
double dy = ty + (rand() * 2 - RAND_MAX) * t;
int now = energy(dx, dy);
double delta = bst - now;
if (delta < 0) {
tx = dx;
ty = dy;
bst = now;
ans =max(ans, now);
}
else if (exp(delta / t) * RAND_MAX < rand()) {
tx = dx;
ty = dy;
bst = now;
}
t *= down;
}
}
map<pair<int, int>, bool> vis;
signed main() {
srand(132052);
cin >> n >> m >> R;
for (int i = 1; i <= n; i++) {
cin >> a[i].x >> a[i].y >> a[i].r;
}
for (int i = 1; i <= m; i++) {
cin >> b[i].x >> b[i].y;
tx += b[i].x;
ty += b[i].y;
}
tx /= m;
ty /= m;
bst = max(bst, energy(tx, ty));
SA();
for (int i = 1; i <= m; i++) {
tx = b[i].x;
ty = b[i].y;
if (((double)clock() / CLOCKS_PER_SEC) > 0.9) break;
if(!vis[{tx, ty}] && rand() % 4 != 0) {
SA();
vis[{tx, ty}] = true;
}
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号