CF1920F1 Smooth Sailing (Easy Version) 题解

news/2024/7/15 19:47:45 标签: 算法, 图论

魔幻暴力题。

题意简述

给你一张 n × m n\times m n×m 的地图,每个点是海 .,岛屿 # 或者火山 v。保证岛屿和非岛屿均可以形成恰好一个四连通块且岛屿不与地图边界接壤,至少有一个岛屿点与一个火山点。

定义一条合法的路径为,从一个非岛屿的点
s s s 出发,每次向四联通的非岛屿点走一格,用航线包围岛屿一整圈后回到点
s s s。一条路径包围岛屿定义为,不存在一条从岛屿出发的八连通路径可以在不触及路径的前提下到达边界。一条路径的权值为途中经过的所有点到离其最近的火山的曼哈顿距离的最小值。

现有 q q q 次询问,每次给定一个点
( x , y ) (x,y) (x,y),你需要求出从 ( x , y ) (x,y) (x,y) 出发的合法路径的最大权值。

3 ≤ n , m ≤ 1 0 5 , 9 ≤ n m ≤ 3 × 1 0 5 , q ≤ 5 3\leq n,m\leq 10^5,9\leq nm\leq 3\times 10^5,q\leq 5 3n,m105,9nm3×105,q5

解题思路

求最小值的最大值,具有单调性,可以二分。难点在于如何 check。

先跑一遍多源最短路把每个点离其最近的火山的曼哈顿距离算出来,记为 d i s i , j dis_{i,j} disi,j。若当前二分出来的答案为 k k k,则我们从询问的点 ( x , y ) (x,y) (x,y) 出发,向四个方向走,只能走 d i s dis dis 值大于等于 k k k 的点,将它们打上标记。

如何判断是否将岛屿围起来?考虑从岛屿点出发,向周围八个方向走,如果能够走到边界且路径上不经过被标记的点,则岛屿没有被完全包围。这个套路在ABC219 E中也用到了。那题也是个暴力题

于是我们就做完了。注意空间的问题,我 vector 用的不太熟练,被卡了好几发。

代码示例

#include<bits/stdc++.h>
using namespace std;
int n,m,Q,stx,sty;
int dx[10]={0,0,1,-1,1,-1,-1,1},dy[10]={1,-1,0,0,1,-1,1,-1};
string s[100010];
vector<int> dis[100010];
vector<bool> Mark[100010],vis[100010];
struct node{
	int x,y;
};
queue<node> q;
void Debug_dis(){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++) cout<<dis[i][j]<<" ";
		cout<<endl;
	}
}
void Debug_Mark_points(int k){
	cout<<"ans:"<<k<<endl;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++) cout<<Mark[i][j]<<" ";
		cout<<endl;
	}
}
void Get_dis(){
	while(!q.empty()) q.pop();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(s[i][j]=='v') dis[i][j]=0,q.push({i,j});
		}
	}
	while(!q.empty()){
		node u=q.front();q.pop();
		for(int i=0;i<4;i++){
			int tx=u.x+dx[i],ty=u.y+dy[i];
			if(tx<1||tx>n||ty<1||ty>m) continue;
			if(dis[tx][ty]>dis[u.x][u.y]+1){
				dis[tx][ty]=dis[u.x][u.y]+1;
				q.push({tx,ty});
			}
		}
	}
}
void Mark_points(int k){
	for(int i=1;i<=n;i++) Mark[i]=vector<bool>(m+5,0);
	while(!q.empty()) q.pop();
	q.push({stx,sty});
	Mark[stx][sty]=1;
	while(!q.empty()){
		node u=q.front();q.pop();
		for(int i=0;i<4;i++){
			int tx=u.x+dx[i],ty=u.y+dy[i];
			if(s[tx][ty]=='#') continue;
			if(tx<1||tx>n||ty<1||ty>m||dis[tx][ty]<k||Mark[tx][ty]) continue;
			Mark[tx][ty]=1;
			q.push({tx,ty});
		}
	}
}
bool check(int k){
	if(dis[stx][sty]<k) return 0;
	Mark_points(k);
	//if(k<=20) Debug_Mark_points(k);
	for(int i=1;i<=n;i++) vis[i]=vector<bool>(m+5,0);
	while(!q.empty()) q.pop();
	int X=0,Y=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++) if(s[i][j]=='#') X=i,Y=j; 
	}
	vis[X][Y]=1;
	q.push({X,Y});
	while(!q.empty()){
		node u=q.front();q.pop();
		for(int i=0;i<8;i++){
			int tx=u.x+dx[i],ty=u.y+dy[i];
			if(tx<1||tx>n||ty<1||ty>m) return 0;
			if(Mark[tx][ty]||vis[tx][ty]) continue;
			vis[tx][ty]=1;
			q.push({tx,ty});
		}
	}
	return 1;
}
void C_close(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
}
int main(){
	C_close();
	cin>>n>>m>>Q;
	for(int i=1;i<=n;i++) cin>>s[i],s[i]=" "+s[i];
	for(int i=1;i<=n;i++) dis[i]=vector<int>(m+5,1e6);
	Get_dis();
	//Debug_dis();
	while(Q--){
		cin>>stx>>sty;
		int l=0,r=n+m+5,ans=0;
		while(l<=r){
			int mid=(l+r)>>1;
			if(check(mid)) l=mid+1,ans=mid;
			else r=mid-1;
		}
		cout<<ans<<endl;
	}
	return 0;
} 

http://www.niftyadmin.cn/n/5352498.html

相关文章

element-ui 树形控件 实现点击某个节点获取本身节点和底下所有的子节点数据

1、需求&#xff1a;点击树形控件中的某个节点&#xff0c;需要拿到它本身和底下所有的子节点的id 1、树形控件代码 <el-tree:data"deptOptions"node-click"getVisitCheckedNodes"ref"target_tree_Speech"node-key"id":default-ex…

###C语言程序设计-----C语言学习(6)#

前言&#xff1a;感谢老铁的浏览&#xff0c;希望老铁可以一键三连加个关注&#xff0c;您的支持和鼓励是我前进的动力&#xff0c;后续会分享更多学习编程的内容。 一. 主干知识的学习 1. while语句 除了for语句以外&#xff0c;while语句也用于实现循环&#xff0c;而且它…

从c到c++——5:内联函数

在调用常规函数时&#xff0c;我们会在它的汇编代码中看到call指令。 如果我们继续调试&#xff0c;如果我们继续调试&#xff0c;会发现执行call会跳转到其他地方&#xff0c;之后会再调用一堆其他的指令&#xff0c;在我的测试&#xff08;vs2022&#xff09;下&#xff1a; …

使用取色器更改主题及颜色时取色器消失问题

问题分析&#xff1a;使用取色器时更改主题颜色时&#xff0c;出现了还没有选择颜色&#xff0c;取色器就消失的现象 1、更改主题颜色实现&#xff1a; <el-form><el-form-item label"主题颜色"><el-color-pickerchange"setColor"v-model…

如何把openwrt的ipk软件包安装到ubuntu上

前提&#xff1a;都是arm64的架构的软件包。 下载openwrt的ipk软件包 1. 从https://pkgs.org/ 查找下载软件包&#xff1a; 本文以swconfig软件包为例&#xff0c;下载swconfig和相关的依赖软件包&#xff1a; swconfig_12_aarch64_cortex-a72.ipk libuci20130104_2021-10-2…

5、主成分分析(Principal Component Analysis)

通过分析变异发现新特征。 文章目录 1、简介2、主成分分析3、PCA用于特征工程4、示例 - 1985年的汽车1、简介 在上一课中,我们研究了我们的第一个基于模型的特征工程方法:聚类。在这一课中,我们将研究我们的下一个方法:主成分分析(PCA)。就像聚类是基于接近度对数据集进…

一天吃透Java集合面试八股文

内容摘自我的学习网站&#xff1a;topjavaer.cn 常见的集合有哪些&#xff1f; Java集合类主要由两个接口Collection和Map派生出来的&#xff0c;Collection有三个子接口&#xff1a;List、Set、Queue。 Java集合框架图如下&#xff1a; List代表了有序可重复集合&#xff0c…

【链表】-Lc23-合并K个有序链表(优先级队列)

写在前面 最近想复习一下数据结构与算法相关的内容&#xff0c;找一些题来做一做。如有更好思路&#xff0c;欢迎指正。 目录 写在前面一、场景描述二、具体步骤1.环境说明2.代码 写在后面 一、场景描述 合并 k 个排序链表&#xff0c;返回合并后的排序链表。请分析和描述算法的…