ABC213 E - Stronger Takahashi 题解

兼 01-BFS 学习笔记

题面

有一个被分为H行W列格子。有的格子可以通行,有的格子有岩石不能通行,不能超过格子。

现在Takahashi在移动过程中,可以一拳破坏2*2的格子中的岩石。

给定地图,请问至少出多少拳破坏岩石,能让Takahashi从左上角走到右下角。

\(H,W\leq 500\)

解题

涨知识了,第一次碰到用 \(01-\text{BFS}\) 做的题目。

本来想到是如何“手动联编” 乱搞建图,然后直接上 \(dijstra\)

瞎 jb 乱搞过后不知道怎么出问题(思路应该是没有问题的),直接就打 \(\text{DFS}\) 暴力了,走人,开 F 题。

那么,什么是 \(01-\text{BFS}\)​ 呢,

我们知道,\(\text{BFS}\) 可以 \(O(V+E)\) 求解边权全为 \(1\) 的图上最短路

而当边权只有 \(0\)\(1\) 时,没必要使用其它最短路算法(并且可能处理方式复杂),此时可以使用 \(01-\text{BFS}\) 来求解,复杂度仍为 \(O(V+E)\).

具体的,\(01-\text{BFS}\) 维护一个双端队列,当边权为 \(0\) 时, \(push\_front\),当边权为 \(1\) 时,\(push\_back\)

正确性?这可以理解为一种贪心的思路,先拓展花费较小的点(有点像 \(SPFA\)\(SLF\) 优化)

重要的是,它同时有 \(bfs\) 的特性,也就是第一次拓展到的就是最小代价。

这样说,\(01-\text{BFS}\) 可以拓展于代价为 \(0\)\(1\) 的两种抉择求代价最少的问题中

代码

应该是可以轻松理解的。

#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int N = 505;

string s[N];
pii zero[]={{0,-1},{0,1},{-1,0},{1,0}};
pii one[]={{0,-1},{0,1},{-1,0},{1,0},
			{-1,-1},{-1,1},{1,-1},{1,1},
			{-2,-1},{-2,0},{-2,1},{2,-1},
			{2,0},{2,1},{-1,-2},{0,-2},
			{1,-2},{-1,2},{0,2},{1,2}
		};
int h,w;

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>h>>w;
	for(int i=0;i<h;++i)
		cin>>s[i];
		
	vector<int>dis(h*w,-1);
	deque<pii >q;
	q.emplace_back(0,0);
	
	while(q.size()){
		auto [u,d]=q.front();q.pop_front();
		if(dis[u]!=-1)continue;
		dis[u]=d;
		for(auto[dx,dy]:zero){
			int x=u/w+dx,y=u%w+dy;
			if(0<=x&&x<h&&0<=y&&y<w&&s[x][y]=='.')
				q.emplace_front(x*w+y,d);
		}
		for(auto[dx,dy]:one){
			int x=u/w+dx,y=u%w+dy;
			if(0<=x&&x<h&&0<=y&&y<w)
				q.emplace_back(x*w+y,d+1);
		}
	}
	
	cout<<dis[h*w-1]<<"\n";
	return 0;
} 
posted @ 2021-08-09 09:23  _Famiglistimo  阅读(157)  评论(0编辑  收藏  举报