其他分享
首页 > 其他分享> > 洛谷P8452 「SWTR-8」15B03题解

洛谷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