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;
}