01bfs 小专题

概括:边权为0/1的图求最短路,常见于网格图的bfs。本质是特殊的dijkstra,因为边权只有0/1,不再需要优先队列维护

Luogu4667
注意需要维护的是格点的坐标和格子的坐标,然后边权如果为0(不换)就push_front,如果为1(换)就push_back

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <deque>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f;

int n,m;
char s[505][505];
deque<pii>dq;
pii ds[] = {mpr(1,1),mpr(1,-1),mpr(-1,1),mpr(-1,-1)};	// 格点坐标 
pii is[] = {mpr(0,0),mpr(0,-1),mpr(-1,0),mpr(-1,-1)};	// 格子坐标 
char cds[] = "\\//\\";
int vis[300005];

int ind(pii x){return x.first * m + x.second;}
int in(pii x){
	return x.first >= 1 && x.first <=n+1 && x.second >=1 && x.second <= m+1;
}

void bfs(){
	memset(vis, 0x3f, sizeof vis);
	vis[ind(mpr(1,1))] = 0;
	dq.push_back(mpr(1,1));
	while(!dq.empty()){
		pii u = dq.front();dq.pop_front();
		for(int i=0;i<4;i++){
			if(cds[i] == s[u.first + is[i].first][u.second + is[i].second]){
				pii v = mpr(u.first + ds[i].first, u.second + ds[i].second);
				if(!in(v))continue;
				if(vis[ind(u)] < vis[ind(v)]){
					vis[ind(v)] = vis[ind(u)];
					dq.push_front(v);
				}
			}else{
				pii v = mpr(u.first + ds[i].first, u.second + ds[i].second);
				if(!in(v))continue;
				if(vis[ind(u)] + 1 < vis[ind(v)]){
					vis[ind(v)] = vis[ind(u)] + 1;
					dq.push_back(v);
				}
			}
		}
	}
	printf("%d\n",vis[ind(mpr(n+1,m+1))]);
}

signed main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%s", s[i] + 1); 
	if((n+m) & 1)return puts("NO SOLUTION"), 0;
	bfs();

	return 0;
}

CF1063B
如果固定终点,则向左的次数确定了则向右的也能确定
因此每次移动转化为了是/不是向左,01bfs解决

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <deque>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2005;

int n,m,r,c,lf,ri;
char s[maxn];
int g[maxn][maxn];
pii dr[] = {mpr(0,-1), mpr(0,1), mpr(1,0), mpr(-1,0)};
deque<pii>dq;
int dis[maxn][maxn];

int in(int x,int y){
	return x >= 1 && x <=n && y >= 1 && y <= m;
}

void bfs(){
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)dis[i][j] = INF;
	dq.push_back(mpr(r,c));
	dis[r][c] = 0;
	while(!dq.empty()){
		pii cur = dq.front();dq.pop_front();
		for(int i = 0;i<4;i++){
			int curx = cur.first + dr[i].first, cury = cur.second + dr[i].second;
			if(!in(curx,cury))continue;
			if(g[curx][cury] == 0)continue;
			int v = i == 0 ? 1 : 0;
			if(dis[cur.first][cur.second] + v < dis[curx][cury]){
				dis[curx][cury] = dis[cur.first][cur.second] + v;
				if(v)dq.push_front(mpr(curx, cury));
				else dq.push_back(mpr(curx, cury));
			}
		}
	}
	int ans = 0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if(!g[i][j])continue;
			int curlf = dis[i][j], curri = (j - c) + curlf;
			if(curlf <= lf && curri <= ri)++ ans;
		}
	printf("%d\n",ans);
}

signed main(){
	scanf("%d%d",&n,&m);
	scanf("%d%d",&r,&c);
	scanf("%d%d",&lf,&ri);
	for(int i=1;i<=n;i++){
		scanf("%s", s + 1);
		for(int j=1;j<=m;j++)
			if(s[j] == '.')
				g[i][j] = 1;
	}
	bfs();

	return 0;
}

Luogu4554
完全一样的做法,移动到相同的位置0,否则为1

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <deque>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f;

int n,m;
char s[505][505];
pii dr[] = {mpr(-1,0),mpr(1,0),mpr(0,-1),mpr(0,1)};
int x1,y1,x2,y2, dis[505][505];
deque<pii>dq;

int in(int x,int y){
	return x >= 1 && x <=n && y >=1 && y <= m; 
}

void bfs(){
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)dis[i][j] = INF;
	dq.push_back(mpr(x1,y1));
	dis[x1][y1] = 0;
	while(!dq.empty()){
		pii u = dq.front(); dq.pop_front();
		for(int i=0;i<4;i++){
			int curx = u.first + dr[i].first, cury = u.second + dr[i].second;
			if(!in(curx,cury))continue;
			int v = 1;
			if(s[u.first][u.second] == s[curx][cury])v = 0;
			if(dis[u.first][u.second] + v < dis[curx][cury]){
				dis[curx][cury] = dis[u.first][u.second] + v;
				if(v == 0)dq.push_front(mpr(curx,cury));
				else dq.push_back(mpr(curx,cury));
			}
		}
	}
	printf("%d\n",dis[x2][y2]);
}

signed main(){
	while(scanf("%d%d",&n,&m), n+m){
		for(int i=1;i<=n;i++)
			scanf("%s", s[i] + 1);
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		++ x1, ++ y1, ++ x2, ++ y2;
		bfs();
	}

	return 0;
}

CF1749E
(想学01bfs就是碰见了这道题)
注意如果按照怪物的路线bfs很难计算答案,考虑思路转化,能够成功当且仅当存在一个仙人掌路径能够从第1列走到第m列,这个路径是八连通且不四连通
0代表接下来还是仙人掌,1代表不是,做01bfs即可
统计路径就记录一下前驱结点即可

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <deque> 
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn=2005;

int n,m;
char s[400005];
int g[400005];
int dis[400005];
int pre[400005];
pii dr[] = {mpr(1,1), mpr(1,-1), mpr(-1,1), mpr(-1,-1)};

int ind(int x,int y){return (x-1) * m + y;}
int in(int x,int y){
	return x >= 1 && x <= n && y >=1 && y <= m;
}
int around(int x,int y){
	pii drr[] = {mpr(0,1),mpr(0,-1),mpr(1,0),mpr(-1,0)};
	for(int i=0;i<4;i++){
		int fx = x + drr[i].first, fy = y + drr[i].second;
		if(!in(fx, fy))continue;
		if(g[ind(fx, fy)])return 1;
	}
	return 0;
}

void solve(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n*m;i++)
		dis[i] = INF, g[i] = 0, pre[i] = -1;
	for(int i=1;i<=n;i++){
		scanf("%s", s + 1);
		for(int j = 1;j<=m;j++){
			if(s[j] == '#'){
				g[ind(i,j)] = 1;
			}
		}
	}
	deque<pii>dq; 
	for(int i=1;i<=n;i++){
		if(g[ind(i,1)] == 1)
			dis[ind(i,1)] = 0, dq.push_front(mpr(i,1));
		else if(!around(i,1))
			dis[ind(i,1)] = 1, dq.push_back(mpr(i, 1));
	}
	while(!dq.empty()){
		pii u = dq.front(); dq.pop_front();
//		printf("%d %d %d\n",u.first,u.second,dis[ind(u.first,u.second)]);
		for(int i=0;i<4;i++){
			int curx = u.first + dr[i].first, cury = u.second + dr[i].second;
			if(!in(curx, cury))continue;
			if(around(curx,cury))continue;
			int v = 0;
			if(g[ind(curx, cury)] == 0)v = 1;
			if(dis[ind(u.first, u.second)] + v < dis[ind(curx,cury)]){
				dis[ind(curx, cury)] = dis[ind(u.first, u.second)] + v;
				pre[ind(curx,cury)] = ind(u.first,u.second);
				if(v == 0)
					dq.push_front(mpr(curx,cury));
				else
					dq.push_back(mpr(curx, cury));
			}
		}
	}
	int ans = INF, ansi;
	for(int i=1;i<=n;i++){
		ans = min(ans, dis[ind(i,m)]);
		if(ans == dis[ind(i,m)])ansi = i;
	}
//	printf("%d %d\n",ansi,ans);
	if(ans == INF)puts("NO");
	else{
		puts("YES");
		int x = ind(ansi, m);
		while(~x){
			g[x] = 1;
			x = pre[x];
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				if(g[ind(i,j)] == 1)putchar('#');
				else putchar('.');
			}
			puts("");
		}
	}
}

signed main(){
	int te;scanf("%d",&te);
	while(te-- )solve();

	return 0;
}
posted @ 2022-11-01 20:48  SkyRainWind  阅读(67)  评论(0编辑  收藏  举报