ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷P8452 「SWTR-8」15B03题解

2022-07-31 17:03:22  阅读:126  来源: 互联网

标签:洛谷 int 题解 long res abs 桌子 double P8452


题目简述

第一问:给定一个大小为\(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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有