【多源01BFS】Codeforce:Three States

题干

翻译

给定一个 n×m 的网格地图,包含以下元素:

  • .:表示荒地(可以修建道路)。

  • #:表示岩石(不可通行)。

  • 数字 1、2、3:分别表示三个国家的位置。

目标:将最少数量的荒地(.)改造成道路,使得三个国家之间互相连通(即任意两国之间存在一条路径)。如果无法实现,输出 -1。

数据范围:

1 ≤ n, m ≤ 1000(即网格最大为 1000×1000)。

分析

  • 三个国家之间两两连通(即 1↔2、1↔3、2↔3 均需有路径)。
  • 路径只能通过荒地(.)或已有数字(国家),不能穿过岩石(#)。
  • 如果三个国家中有任意一个被岩石包围,无法与其他国家连通,则输出 -1。

面对这题可能先想到的就是求出每一个荒地到每一个国家的最短距离,求一个点到矩阵中其他所有点的距离就要进行一次完整的BFS,如果现在求所有荒地到其他点的最短距离,那么时间复杂度就会相当高,而且还存在非常多的细节判断,比如某两个国家是连通的,但是依次求每个荒地到国家的最短距离,是不能直接判断国家是否连通的,如果两个国家连通,荒地到最近的那个国家就行了,是不用再去找另外一个国家的,这就又需要单独处理这种情况,此外还有很多情况就不一一举例了。

总之,正难则反,这题我们反过来思考,求荒地到各个国家的最短距离难,那我们就求每个国家到荒地的距离,这样就只用分三个情况,因为只有三个国家,每个国家在求到所有荒地的距离的时候就是一次多源BFS。所以这题就只需要进行三次多源+01BFS就解决了,最后再统计哪个点到三个国家的距离之和最短,那就是我们想要的答案。

题解

cpp 复制代码
#include<iostream> 
#include<deque>
#include<cstring>
using namespace std;
typedef pair<int,int> PII;
int n,m;
const int N = 1e3 + 10;
char p[N][N];
int dist[4][N][N];

int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};

void bfs(int pos)
{
	memset(dist[pos],-1,sizeof dist[pos]);
	
	//多源BFS 
	deque<PII> q;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(p[i][j] - '0' == pos)
			{
				q.push_front({i,j});
				dist[pos][i][j] = 0;
			}	
		} 
	}	
	
	//01BFS
	while(q.size())
	{
		auto t = q.front(); q.pop_front();
		int x = t.first, y = t.second;
		for(int i=0;i<4;i++)
		{
			int a = x + dx[i], b = y + dy[i];
			if(a >= 1 && a <= n && b >= 1 && b <= m && p[a][b] != '#') //跳过非法
			{
				//计算边权 
				int w = (p[a][b] == '.' ? 1 : 0);
			 
				//第一次访问(一定要入队) 
				if(dist[pos][a][b] == -1)
				{
					dist[pos][a][b] = dist[pos][x][y] + w;
					if(w) q.push_back({a,b});
					else q.push_front({a,b});
				}
				//再次访问比大小 
				else if(dist[pos][x][y] + w < dist[pos][a][b])
				{
					//松弛 
					dist[pos][a][b] = dist[pos][x][y] + w;
				} 					
			}
		}
	}
}

int main()
{
	cin >> n >> m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin >> p[i][j];	
		} 
	}	
	
	bfs(1);
	bfs(2);
	bfs(3);
	
	int ret = 0x3f3f3f3f;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(p[i][j] == '#') continue;
			//把合法的位置距离1、2、3号国家的距离全部提取出来 
			int x = dist[1][i][j], y = dist[2][i][j], z = dist[3][i][j];
			//即使合法了,这个位置也可能到不了,这样的点是不能参与更新结果的 
			if(x == -1 || y == -1 || z == -1) continue; 
			//判断这个位置是在荒地上还是在国家上
			if(p[i][j] == '.') ret = min(ret,x + y + z - 2); 
			//注意这里-2是为了减掉重复计算的路程,我们再以某个点为中心计算它到三个国家的距离的时候,这个点只需要计算一次,所以就减去多余算上的两次
			else ret = min(ret,x + y + z); 
		} 
	}
	
	//判断ret
	if(ret == 0x3f3f3f3f) cout << -1 << endl;
	else cout << ret << endl; 
	return 0;
}
相关推荐
MaisieKim_26 分钟前
如何实现 C/C++ 与 Python 的通信
c语言·c++·python
蒟蒻小袁2 小时前
力扣面试150题--二叉树的层平均值
算法·leetcode·面试
geneculture2 小时前
技术-工程-管用养修保-智能硬件-智能软件五维黄金序位模型
大数据·人工智能·算法·数学建模·智能硬件·工程技术·融智学的重要应用
1001101_QIA2 小时前
【QT】理解QT机制之“元对象系统”
开发语言·c++·qt·算法
a东方青2 小时前
[蓝桥杯C++ 2024 国 B ] 立定跳远(二分)
c++·算法·蓝桥杯·c++20
Studying 开龙wu2 小时前
机器学习无监督学习sklearn实战一:K-Means 算法聚类对葡萄酒数据集进行聚类分析和可视化( 主成分分析PCA特征降维)
算法·机器学习·sklearn
似水এ᭄往昔2 小时前
【数据结构】--二叉树--堆(上)
数据结构·算法
心软且酷丶3 小时前
leetcode:479. 最大回文数乘积(python3解法,数学相关算法题)
python·算法·leetcode
里欧布鲁斯3 小时前
Sums of Sliding Window Maximum_abc407F分析与解答
算法
2501_915373883 小时前
Java调用C++教程:JNI与JNA两种方式详解
java·开发语言·c++