首页 > 其他分享 >P2218 题解

P2218 题解

时间:2022-10-22 19:47:44浏览次数:96  
标签:int 题解 dfs dict max P2218 cases inf

前言

题目传送门!

更好的阅读体验?

二分答案套搜索。

思路

答案显然具有单调性,于是可以二分答案。

问题是如何实现 \(\operatorname{check}(k)\) 函数(\(k\) 指薄膜边长)。

其实很简单:用 dfs 即可。

每次 dfs 时记录下当前是第几个薄膜。dfs 时,如果 \(\max\big(\small(\max x_i) - (\min x_i), (\max y_i) - (\min y_i)\big)\small \le k\),说明 \(k\) 是可行解。

bool dfs(int c)
{
	int minx = inf, maxx = -inf, miny = inf, maxy = -inf;
	for (int i = 1; i <= n; i++)
		if (!flag[i])
			minx = min(minx, x[i]), maxx = max(maxx, x[i]), miny = min(miny, y[i]), maxy = max(maxy, y[i]);
	if (max(maxx - minx, maxy - miny) <= k) return true; //可以安装完
	if (c == 3) return false;
        //write other code here
}

覆盖时,考虑薄膜左上角与右下角的位置。看起来有很多情况,其实很少。

假设点分布的很不均匀,然后我们在中间的部分放一个薄膜。

这时,你会发现,边角上的点仍然要处理。这样,你不得不再花费薄膜在边角上放置,非常浪费。


因此,最好的方法就是全部贴着角放

所以,左上角 \((x1, y1)\) 以及右下角 \((x2, y2)\),一共只有四种可能

横坐标两种可能:\(\begin{cases}x1 = (\min x_i) \\x2 = (\min x_i) + k\end{cases}\ \ \begin{cases}x1 = (\max x_i) - k \\x2 = (\max x_i)\end{cases}\)

同理,纵坐标有两种可能:\(\begin{cases}y1 = (\min y_i) \\y2 = (\min y_i) + k\end{cases}\ \ \begin{cases}y1 = (\max y_i) - k \\y2 = (\max y_i)\end{cases}\)

两两搭配就是四种了。具体可以见代码。

int dict[4][4]; //自己对比一下,依次指 x1, x2, y1, y2
dict[0][0] = minx, dict[0][1] = minx + k, dict[0][2] = miny, dict[0][3] = miny + k;
dict[1][0] = minx, dict[1][1] = minx + k, dict[1][2] = maxy - k, dict[1][3] = maxy;
dict[2][0] = maxx - k, dict[2][1] = maxx, dict[2][2] = miny, dict[2][3] = miny + k;
dict[3][0] = maxx - k, dict[3][1] = maxx, dict[3][2] = maxy - k, dict[3][3] = maxy;

依次枚举这四种情况,覆盖时暴力看能否盖住即可。

搜完后记得回溯。

for (int j = 0; j < 4; j++)
{
	int x1 = dict[j][0], x2 = dict[j][1], y1 = dict[j][2], y2 = dict[j][3];
	for (int i = 1; i <= n; i++) //覆盖
		if (!flag[i])
			if (x1 <= x[i] && x[i] <= x2 && y1 <= y[i] && y[i] <= y2)
				flag[i] = c;
	if (dfs(c + 1)) return true;
	for (int i = 1; i <= n; i++) //回溯
		if (flag[i] == c)
			flag[i] = 0;
}

坑点

  1. 数组要清空!

  2. 正如这篇题解所说,大部分变量都需要定义在函数内!
    比如本代码的 dict 数组,就一定要定义在 dfs 里,很诡异。

完整代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 20005, inf = 2147483647;
int x[N], y[N], flag[N]; //flag:是否已经被覆盖了
int k, n;
inline bool dfs(int c)
{
	int minx = inf, maxx = -inf, miny = inf, maxy = -inf;
	for (int i = 1; i <= n; i++)
		if (!flag[i])
			minx = min(minx, x[i]), maxx = max(maxx, x[i]), miny = min(miny, y[i]), maxy = max(maxy, y[i]);
	if (max(maxx - minx, maxy - miny) <= k) return true; //可以安装完
	if (c == 3) return false;
	int dict[4][4]; //自己对比一下,依次指 x1, x2, y1, y2
	dict[0][0] = minx, dict[0][1] = minx + k, dict[0][2] = miny, dict[0][3] = miny + k;
	dict[1][0] = minx, dict[1][1] = minx + k, dict[1][2] = maxy - k, dict[1][3] = maxy;
	dict[2][0] = maxx - k, dict[2][1] = maxx, dict[2][2] = miny, dict[2][3] = miny + k;
	dict[3][0] = maxx - k, dict[3][1] = maxx, dict[3][2] = maxy - k, dict[3][3] = maxy;
	for (int j = 0; j < 4; j++)
	{
		int x1 = dict[j][0], x2 = dict[j][1], y1 = dict[j][2], y2 = dict[j][3];
		for (int i = 1; i <= n; i++) //覆盖
			if (!flag[i])
				if (x1 <= x[i] && x[i] <= x2 && y1 <= y[i] && y[i] <= y2)
					flag[i] = c;
		if (dfs(c + 1)) return true;
		for (int i = 1; i <= n; i++) //回溯
			if (flag[i] == c)
				flag[i] = 0;
	}
	return false;
}
bool chk(int oh)
{
	k = oh;
	for (int i = 1; i <= n; i++) flag[i] = 0;
	return dfs(1);
}
int FIND(LL l, LL r)
{
	while (l < r) //FFFF【T】TTT
	{
		LL mid = (l + r) >> 1;
		if (chk(mid)) r = mid;
		else l = mid + 1;
	}
	return r;
}
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) scanf("%d%d", &x[i], &y[i]);
	cout << FIND(0, 2e9);
	return 0;
}

希望能帮助到大家!

标签:int,题解,dfs,dict,max,P2218,cases,inf
From: https://www.cnblogs.com/liangbowen/p/16817123.html

相关文章

  • 洛谷P2827题解
    原题P2827[NOIP2016提高组]蚯蚓思路概述题意分析给定整数\(n,m,q,u,v,t\)和一个数列\(\{a\}\),进行\(m\)次操作如下:每次选取其中最大数\(x\)切分为\([px],x......
  • dremio 21 版本之后反射No File System scheme matches 问题解决
    实际属于一个老问题了,整理下,方便使用,主要是我们在使用反射的时候碰到的问题问题如下UnknownFormatConversionException:Conversion='Unknownformat(pdfs)conversio......
  • CodeForces-1143#C 题解
    正文♦时间复杂度:\(\mathcal{O}(n)\)思维题,不需要建树。设数组\(a\)记录每一个节点是否尊重它的父节点,数组\(b\)记录是否有节点尊重它,特别的,叶子节点必然不被尊重。......
  • [题解]如何求连续区间最大和
    给一个数列,有正有负,如何求最大的连续区间和?需要设f数组表示每个位置为结尾的最大区间和能否让f[i]等于f[i-1]+a[i]要看这样的f[i]是否大于零如果大于0,就说明它仍然可以......
  • 「题解」洛谷 P8529 [Ynoi2003] 赫露艾斯塔
    构造半平面莫队?/jk注意到对于一个半平面的直线,通过平移和旋转经过的点数,一定大于等于它们的对称差,因为对称差中的点会被经过奇数次,不在对称差中的点会被经过偶数次。那么......
  • ABC266 ~ 273 题解
    缺省源#pragmaGCCoptimize(3)#include<bits/stdc++.h>namespace//tofoldthatjunkcode{#definefilein(x){freopen(x".in","r",stdin);}#definefile(......
  • Fabricating Sculptures 题解
    草草地写一篇题解,废话不多说暴力要拼成“^”型,考虑\(DP\)令\(f_{i,j}\)表示,总共有\(i\)个积木,其中底座占了\(j\)个积木,也就是说你还有\(i-j\)个积木来拼底座的......
  • CF1716C Robot in a Hallway题解
    \(2000\)分的DP题。题意给定一个\(2\)行\(n\)列的网格。机器人初始坐标为\((0,1)\),每一秒都可以向四周移动。每个格子有解锁时间,在该时间之前机器人不可以进入该......
  • CF1045G 题解
    前言题目传送门!更好的阅读体验?和模版稍有不同的cdq分治。思路cdq是离线算法,所以我们可以先给\(x_i\)离散化一下。同时,记录下\((x_i-r_i)\)与\((x_i+r_i)......
  • 关于LoRa常见问题解答
    前面的文章中,小编有写过LORA技术低功耗广域网络,在大大小小的行业活动中,一直都是物联网的一个热门话题。LoRa主要在全球免费频段运行,包括433、868、915MHz等。后来有很多......