首页 > 其他分享 >P2130 题解

P2130 题解

时间:2022-08-26 02:00:27浏览次数:87  
标签:int 题解 sum P2130 x2 dy y1 y2

前言

题目传送门!

更好的阅读体验?

本题是练习 bfs 的好题。

思路

结合代码进行思路讲解。

首先是读入部分,我们可以用 bool 存下地图,节省空间开销。

需要注意,数据比较烂,起始点可能有障碍

我们可以霸气地把起始点的障碍消掉。

const int N = 1005;
bool a[N][N];
int n, m, fx, fy;
void Input() //简单的输入。我们可以用 bool 存地图,减少空间开销。 
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			char x;
			cin >> x;
			if (x == '$' || x == '.') a[i][j] = true;
			if (x == 'X') a[i][j] = false;
			if (x == '#') fx = i, fy = j, a[i][j] = true;
		}
	a[1][1] = true; //本题数据很烂,(1,1) 可能有障碍,需要手动消除。 
}

然后就是 bfs 了。在 bfs 之前,我们准备一堆移动数组:

//这些是用来记录答案的数组。 
struct Node {int x, y;};
int ans[N][N];
bool vis[N][N];

//下面这个,是记录步数的表格(个人习惯下标从 1 开始)。
int foot[15] = {0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
//下面这个,是上下左右的方位数组(个人习惯下标从 1 开始)。
int dict[5][2] = {{0, 0}, {1, 0}, {-1, 0}, {0, 1}, {0, -1}}; 

本题最特殊的地方在于,每一步走动之间不能有障碍。这是显然的事情。

因此,我们可以在 bfs 中用函数 \(\texttt{run()}\) 判断能否走动。

具体如下:

int bfs() //基本上和 bfs 的模版区别不大。
{
	queue <Node> Q;
	ans[1][1] = 0, vis[1][1] = true;
	Q.push( (Node){1, 1} );
	while (!Q.empty())
	{
		int x = Q.front().x, y = Q.front().y;
		//cout << "x = " << x << ", y = " << y << ".\n";
		if (x == fx && y == fy) return ans[x][y];
		Q.pop();
		for (int i = 1; i <= 4; i++)
			for (int j = 1; j <= 10; j++)
			{
			    //以下稍微有点特殊。
				int dx = x + dict[i][0] * foot[j], dy = y + dict[i][1] * foot[j];
				if (dx < 1 || dx > n || dy < 1 || dy > m) continue;
				if (!run(x, y, dx, dy) || vis[dx][dy]) continue;
				ans[dx][dy] = ans[x][y] + 1, vis[dx][dy] = true;
				Q.push( (Node){dx, dy} );
			}
	}
	return -1;
}

观察这份代码,容易发现,时间复杂度 \(O(n\times m \times\log n)\) 加上 \(\texttt{run()}\) 的时间复杂度。

如果 \(\texttt{run()}\) 仍然暴力枚举,时间复杂度将会是 \(O(n\times m \times\log^2 n)\),极大可能超时。

因此,我们试图让 \(\texttt{run()}\) 函数 \(O(1)\) 计算。


事实上,我们可以前缀和优化它。

具体地,设 \(sum_{i, j}\) 表示 \((1,1)\) 到 \((i,j)\) 的矩阵中,不可以走的点的个数。

这个就是典型的二维前缀和:\(sum_{i, j} = sum_{i-1,j} + sum_{i, j-1} - sum_{i-1,j-1} + [a_{i,j} = false]\)。

//sum[i][j] 表示 (1,1) 到 (i,j) 的矩阵中,不可以走的点的个数。 
int sum[N][N];
void init() //预处理前缀和。 
{
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + (a[i][j] == false);
	//for(int i=1;i<=n;i++,cout<<'\n')for(int j=1;j<=m;j++)cout<<sum[i][j]<<' ';
}

那么,\(\texttt{run()}\) 只需要让 \((x1,y1)\) 到 \((x2,y2)\) 的矩阵中,无法走的点的数量为 \(0\) 即可。

bool run(int x1, int y1, int x2, int y2) //判断能否从 (x1,y1) 到 (x2,y2)。 
{
	if (x1 > x2 || y1 > y2) swap(x1, x2), swap(y1, y2);
	int s = sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1];
	return (s == 0);
}

至此,本题结束。时间复杂度上文已经提到,是 \(O(n^2 \log n)\) 级别的。

完整代码

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
void Fastio()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);	
}
const int N = 1005;
bool a[N][N];
int n, m, fx, fy;
void Input() //简单的输入。我们可以用 bool 存地图,减少空间开销。 
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			char x;
			cin >> x;
			if (x == '$' || x == '.') a[i][j] = true;
			if (x == 'X') a[i][j] = false;
			if (x == '#') fx = i, fy = j, a[i][j] = true;
		}
	a[1][1] = true; //本题数据很烂,(1,1) 可能有障碍,需要手动消除。 
}

//sum[i][j] 表示 (1,1) 到 (i,j) 的矩阵中,不可以走的点的个数。 
int sum[N][N];
void init() //预处理前缀和。 
{
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + (a[i][j] == false);
	//for(int i=1;i<=n;i++,cout<<'\n')for(int j=1;j<=m;j++)cout<<sum[i][j]<<' ';
}

bool run(int x1, int y1, int x2, int y2) //判断能否从 (x1,y1) 到 (x2,y2)。 
{
	if (x1 > x2 || y1 > y2) swap(x1, x2), swap(y1, y2);
	int s = sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1];
	return (s == 0);
}

//这些是用来记录答案的数组。 
struct Node {int x, y;};
int ans[N][N];
bool vis[N][N];

//下面这个,是记录步数的表格(个人习惯下标从 1 开始)。
int foot[15] = {0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
//下面这个,是上下左右的方位数组(个人习惯下标从 1 开始)。
int dict[5][2] = {{0, 0}, {1, 0}, {-1, 0}, {0, 1}, {0, -1}}; 

int bfs()
{
	queue <Node> Q;
	ans[1][1] = 0, vis[1][1] = true;
	Q.push( (Node){1, 1} );
	while (!Q.empty())
	{
		int x = Q.front().x, y = Q.front().y;
		//cout << "x = " << x << ", y = " << y << ".\n";
		if (x == fx && y == fy) return ans[x][y];
		Q.pop();
		for (int i = 1; i <= 4; i++)
			for (int j = 1; j <= 10; j++)
			{
			    //以下稍微有点特殊。
				int dx = x + dict[i][0] * foot[j], dy = y + dict[i][1] * foot[j];
				if (dx < 1 || dx > n || dy < 1 || dy > m) continue;
				if (!run(x, y, dx, dy) || vis[dx][dy]) continue;
				ans[dx][dy] = ans[x][y] + 1, vis[dx][dy] = true;
				Q.push( (Node){dx, dy} );
			}
	}
	return -1;
}
int main()
{
	Fastio();
	Input();
	init();
	cout << bfs();
	return 0;
}

希望能帮助到大家!
首发:2022-07-08 14:58:46

标签:int,题解,sum,P2130,x2,dy,y1,y2
From: https://www.cnblogs.com/liangbowen/p/16622895.html

相关文章

  • CF1635B 题解
    题目传送门!更好的阅读体验?这题显然可以使用贪心的思想解决。由于头和尾一定不用更改,所以只需从\(a_2\)枚举到\(a_{n-1}\)。贪心原则下,我们更改的数应该要与相邻的......
  • P8295 题解
    ###前言题目传送门\(\color{red}{see}\space\color{green}{in}\space\color{blue}{my}\space\color{purple}{blog}\)这题并不困难,代码也挺短的,题目理解稍有困难。......
  • 题解 UVA10869 Brownie Points II
    题意平面上有若干点,\(\text{stan}\)通过一个点划了一条直线,\(\text{ollie}\)通过在这条直线上的点作了一条垂线,那么平面被分成\(4\)个象限,\(\text{stan}\)获得的分数......
  • idea导入依赖maven的dependenci列表报红问题解决
    打开一个idea的pom文件时,明明仓库有相关依赖,并且maven的仓库配置没有错误,但是maven的dependencies列表却报红,我们可以让idea每次加载pom文件的依赖不从idea的缓存中读取,而......
  • npm 报错:npm ERR! Maximum call stack size exceeded 超过最大栈问题解决方案
       错误的原因,npm版本问题;解决办法:   1、更新到最新版本:npminstallnpm-g  要记住全局更新2、回退版本:[email protected] ......
  • 蔚来杯2022牛客暑期多校训练营10 题解
    D.MiReDoSiLa?SoFa![NOI2016]优秀的拆分原题。枚举周期\(k\),并将位置为\(k\)的倍数的点设为关键点。枚举相邻两个点\(i,i+k\),并求出\(lcp(S[i...n],S[i+k......
  • 2022“杭电杯”中国大学生算法设计超级联赛(10) 题解
    C.WavyTree发现修改次数和相邻两数的相对大小有关,所以可先求出差分数组。分两种情况考虑:①奇数位置为波峰②偶数位置为波峰。以情况①为例,若奇数位置差分后值小......
  • Idea创建Maven Web工程的web.xml版本问题解决
    问题使用Maven创建web工程的时候,创建出来的web.xml版本有问题。临时解决方案将在Tomcat安装目录下的webapps/ROOT/WEB-INF下的web.xml替换项目下的web.xml......
  • jmeter-特殊问题解决
    1、相应报文乱码问题:方法一:1、在相应节点的下方,比如http请求,添加后置处理器–》BeanShellPostProcessor2、然后在其脚本框中添加如下代码prev.setDataEncoding(“UTF-8......
  • 【问题解决】npm ERR! code EINTEGRITY
    问题说明Jenkins构建前端安装依赖报错:npmERR!codeEINTEGRITY11:05:42npmERR!sha512-IJy2B5Ot9wIAGwjSKF94+8yhVCQUDBT4myzlswuJSNPcLcn3Jna3yPNOmp/mbXfPPSNFwV9......