洛谷P8452 「SWTR-8」15B03题解
作者:互联网
题目简述
第一问:给定一个大小为\(n\times m\)的网格,每个网格上有一张桌子,求最少去掉多少张桌子才能满足 $\forall (i,j) $ , $ (i', j'),|i - i'|\leq 1$ 且 \(|j - j'|\leq 1\) 。
第二问:在保证撤去桌子最少的前提下,最大化剩余每张桌子到距离它最远的桌子的距离之和。这里距离指 欧几里得 距离:桌子 \((a, b)\) 和 \((c, d)\) 的距离为 \(\sqrt{(a - c) ^ 2 + (b - d) ^ 2}\)。
题目分析
为了使撤去桌子数量最少,我们可以考虑让第一张桌子放在左上角的位置,之后向右每隔一个空放一个桌子,向下每隔一个空放置一个桌子,即从\((1,1)\)出发,如果\((i,j)\)上存在一张桌子,那么在 \((i+2,j)\) 和 \((i,j+2)\) 上放置一张桌子。我们可以看成一个桌子在X轴或Y轴方向上占两个空,这样算出每行最多放置的桌子数量和每列最多放置的桌子数量,相乘即可得到剩余桌子的最大数量,再减去总的数量即可得到去掉的桌子的数量。
即\(n\times m-\left\lceil\dfrac{n}{2}\right\rceil \times\left\lceil\dfrac{m}{2}\right\rceil\)。
代码如下
#include <bits/stdc++.h>
using namespace std;
int s, t, n, m;
int main() {
scanf("%d", &s);
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
int x = n >> 1, y = m >> 1;//位运算,n>>1=n/2。
if (n & 1) {
x++;// 如果是奇数,在另一端还能再放置一张桌子
}
if (m & 1) {
y++;
}
printf("%d %0.2Lf\n", n * m - x * y, (long double)rand());
}
return 0;
}
这样80分就到手了。
100分做法
第二问如果按照上面的做法的话会被样例中第二组数据卡掉,因为按上面的思路的话位于\((1, 1)\) 和 \((1, 3)\)上的桌子会被留下但最优的情况应该是留下 \((1, 1)\) 和 \((2, 4)\) 上的桌子。
所以我们可以考虑利用BFS的思想枚举每一张桌子,首先在队列中加入位于 \((1,1)\) 和 \((n,m)\) 上的桌子,同时用一个数组把位于桌子和桌子周围的格子标记 如果 \((n,1)\) 和 \((1,m)\) 没有被标记也把这两个位置加入队列,之后在进行BFS的时候对于每个在队列中的点 \((i,j)\) ,遍历一遍位于 \((i+2,j)\) , \((i-2,j)\) , \((i,j+2)\) , \((i,j-2)\) 上的点,如果没有被标记,就把对应的点加入队列,加入队列的同时把它周围的所有点进行标记。
对于统计答案,可以考虑在遍历到某个点时,根据贪心的思想,计算这个点到四个顶点的最大值,当左下角或右上角没有桌子的时候,易证离该桌子最远的桌子一定位于左上角或者右下角。
特殊情况
当剩余桌子数量为 \(1\) 时,直接输出 \(0\) ,然后进入下一层循环就好了。
代码
#include <bits/stdc++.h>
using namespace std;
int s, t, n, m;
int px[4] = {2, -2, 0, 0};
int py[4] = {0, 0, 2, -2};
long double ans = 0;
vector <int> xs, ys;
bool v[1067][1067];
queue <int> xq, yq;
long double max(long double a, long double b, long double c, long double d) {
long double res = a;
if (b > res) {
res = b;
}
if (c > res) {
res = c;
}
if (d > res) {
res = d;
}
return res;
}
int main() {
scanf("%d", &s);
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
ans = 0.0;
memset(v, 0, sizeof(v));
int _x = n >> 1, _y = m >> 1;
if (n & 1) {
_x++;
}
if (m & 1) {
_y++;
}
printf("%d ", n * m - _x * _y);
if (_x * _y == 1) {
printf("0.000000000\n");
continue;
}
v[1][1] = 1;
v[n][m] = 1;
xq.push(1), yq.push(1);
xq.push(n), yq.push(m);
v[2][1] = v[1][2] = v[2][2] = 1;
v[n][m - 1] = v[n - 1][m] = v[n - 1][m - 1] = 1;
if (!v[1][m]) {
xq.push(1), yq.push(m);
v[1][m] = v[2][m] = v[1][m - 1] = v[2][m - 1] = 1;
}
if (!v[n][1]) {
xq.push(n), yq.push(1);
v[n][1] = v[n][2] = v[n - 1][2] = v[n - 1][1] = 1;
}
while (!xq.empty()) {
int x = xq.front(), y = yq.front();
xq.pop(), yq.pop();
ans += (long double)max(sqrtl(abs(x - 1) * abs(x - 1) + abs(y - 1) * abs(y - 1)),
sqrtl(abs(x - n) * abs(x - n) + abs(y - 1) * abs(y - 1)), sqrtl(abs(x - 1) * abs(x - 1) + abs(y - m) * abs(y - m)),
sqrtl(abs(x - n) * abs(x - n) + abs(y - m) * abs(y - m)));
for (int i = 0; i < 4; i++) {
int nx = x + px[i], ny = y + py[i];
if ( nx > 0 && nx <= n && ny > 0 && ny <= m && !v[nx][ny]) {
v[nx][ny] = v[nx + 1][ny] = v[nx - 1][ny] = v[nx][ny + 1] = v[nx][ny - 1] = v[nx + 1][ny + 1] = v[nx + 1][ny - 1] = 1;
v[nx - 1][ny + 1] = v[nx - 1][ny - 1] = 1;
xq.push(nx), yq.push(ny);
}
}
}
printf("%0.9Lf\n", ans);
}
return 0;
}
标签:洛谷,int,题解,long,res,abs,桌子,double,P8452 来源: https://www.cnblogs.com/Dregen-Yor/p/16537497.html