睿爸334

chrispang發表於2024-08-21

題目傳送門

說明

“哞林匹克”運動會中的一大亮點就是滑雪比賽。滑雪比賽的場地是一個 \(n \times m\) 的矩陣(\(1<=n,m<=500\)),每一個點有對應的海拔(海拔均在 \(0\)\(10^9\) 的範圍內)。

主機板方指定了若干個點作為路標。同時,主辦方還要規定一個比賽係數 \(d\) ,這個係數規定選手不能在海拔高度差大於 \(d\) 的兩個點之間活動。在規則允許的範圍內,選手可以向東南西北任意一個點活動,選手的任務是在儘量短的時間內到達所有的路標打卡。

為了確保每一個選手的安全,主辦方想將係數d設定得越小越好,然而這個係數要確保每一個路標是相互聯通的(否則比賽就失去了意義)。

輸入格式

第一行輸入兩個整數n和m,表示比賽場地的大小;

接下來輸入兩個 \(n \times m\) 的矩陣,第一個表示每一個點的海拔高度,第二個矩陣表示路標的設定情況,其中數字 \(1\) 表示該點為路標,數字 \(0\) 表示不是路標。

輸出格式

輸出 \(d\)

樣例

輸入資料 \(1\)

3 5
20 21 18 99 5
19 22 20 16 26
18 17 40 60 80
1 0 0 0 1
0 0 0 0 0
0 0 0 0 1

輸出資料 \(1\)

21

-------------------------------------------------------

分析

本題每次列舉 \(d\)。每次 BFS 遍歷一遍地圖,如果發現一個點到另一個點距離大於 \(d\) 的話,則不走這條路。否則把這個新的點加入佇列。

不過本題的 \(d\) 高達 \(10^9\),所以暴力列舉肯定是不行的,因此,我們就要用上二分答案來解決這道題了。

程式碼

#include <bits/stdc++.h>
#define int long long //開個long long,以防萬一 
using namespace std;

int n, m, l = 0, r = 1e9, ans = INT_MAX, map1[510][510], map2[510][510]; //map1表示地圖,map2表示打卡點 
int dx[4] = {0, 1, 0, -1}; //方位陣列 
int dy[4] = {1, 0, -1, 0};
bool vis[510][510];
struct node {
	int x, y; //記錄一個座標 
};

bool check(int d) {
	memset(vis, 0, sizeof(vis)); //更新陣列 
	vis[1][1] = 1; //起點設為1 
	queue<node>q;
	q.push({1, 1}); //把起點放進去 
	while(!q.empty()) {
		int x = q.front().x; //取出隊頭元素 
		int y = q.front().y;
		q.pop();
		for (int i = 0; i < 4; i++) {
			int tx = x + dx[i], ty = y + dy[i]; //新的一個座標 
			if(tx < 1 || tx > n || ty < 1 || ty > m || vis[tx][ty] || abs(map1[x][y] - map1[tx][ty]) > d) continue; //判斷是否可以到達新的點 
			q.push({tx, ty}); //放入佇列 
			vis[tx][ty] = 1; //進行記錄 
		}
	}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			if(map2[i][j] && !vis[i][j]) //如果這個點是打卡點並且還沒有走到 
				return 0; //則返回0 
	return 1; //否則返回1 
}

signed main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			cin >> map1[i][j];
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			cin >> map2[i][j];
	while(l <= r) {
		int mid = (l + r) / 2;
		if(check(mid)) ans = min(mid, ans), r = mid - 1; //如果可以,記錄答案,並且看看能否找到更小的 
		else l = mid + 1; //否則找更大的 
	}
	cout << ans << endl;
	return 0;
}

相關文章