迷宫问题
从左上角到右下角的最短路径,输出最短路径
BFS入队时记录(nx,ny)的上一点(x,y), 输出路径时从终点开始回溯,到起点停止
#include<bits/stdc++.h>
using namespace std;
#define fast(); ios::sync_with_stdio(false);cin,tie(0),cout.tie(0);
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e3+5;
int n;
int dx[]={0,-1,0,1};
int dy[]={-1,0,1,0};
int w[N][N];
int vis[N][N];
PII path[N][N];
void bfs(int x,int y){
queue<PII> q;
q.push({0,0});
vis[0][0]=true;
while(!q.empty()){
PII t=q.front();q.pop();
int x=t.first,y=t.second;
if(x==n-1&&y==n-1) break;
for(int i=0;i<4;i++){
int nx=x+dx[i],ny=y+dy[i];
if(nx<0||ny<0||nx>=n||ny>=n) continue;
if(w[nx][ny]==1) continue;
if(vis[nx][ny]) continue;
vis[nx][ny]=true;
q.push({nx,ny});
path[nx][ny]={x,y};//记录路径
}
}
}
int main(){
cin>>n;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>w[i][j];
}
}
bfs(0,0);
//输出路径,从终点开始回溯,到起点停止
vector<PII> vc;
int x=n-1,y=n-1;
vc.push_back({x,y});
do{
PII t=path[x][y];
x=t.first,y=t.second;
vc.push_back({x,y});
}while(x!=0||y!=0);
reverse(vc.begin(),vc.end());
for(auto t:vc){
cout<<t.first<<" "<<t.second<<endl;
}
}
武士风度的牛
马走日,从起点到终点的最小步数
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
int n,m;
const int N=1e3+5;
char g[N][N];
int dx[]={2,-2,2,-2,1,1,-1,-1};
int dy[]={1,1,-1,-1,2,-2,2,-2};
PII st,ed;
bool vis[N][N];
int dis[N][N];
void bfs(){
queue<PII> q;
q.push({st.first,st.second});
vis[st.first][st.second]=true;
while(!q.empty()){
PII t=q.front();q.pop();
int x=t.first,y=t.second;
if(x==ed.first&&y==ed.second) break;
for(int i=0;i<8;i++){
int nx=x+dx[i],ny=y+dy[i];
if(nx<1||ny<1||nx>n||ny>m) continue;
if(g[nx][ny]=='*') continue;
if(vis[nx][ny]) continue;
vis[nx][ny]=true;
q.push({nx,ny});
dis[nx][ny]=dis[x][y]+1;//记录步数
}
}
}
int main(){
cin>>m>>n;
for(int i=1;i<=n;i++){
cin>>g[i]+1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(g[i][j]=='K') st={i,j};
if(g[i][j]=='H') ed={i,j};
}
}
bfs();
cout<<dis[ed.first][ed.second];
}
矩阵距离(多源BFS)
01矩阵,每个0距离最近的1的距离
将所有1入队进行BFS,记录搜到的每个点的距离,即0到最近的1的距离
注意:初始入队时,将每个1的vis标记为true,搜索时只入队0
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
int n,m;
const int N=1e3+5;
char g[N][N];
int dx[]={0,1,-1,0};
int dy[]={1,0,0,-1};
PII st,ed;
bool vis[N][N];
int dis[N][N];
void bfs(){
queue<PII> q;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(g[i][j]=='1'){
q.push({i,j});
vis[i][j]=true;
}
}
}
while(!q.empty()){
PII t=q.front();q.pop();
int x=t.first,y=t.second;
for(int i=0;i<4;i++){
int nx=x+dx[i],ny=y+dy[i];
if(nx<1||ny<1||nx>n||ny>m) continue;
if(vis[nx][ny]) continue;
vis[nx][ny]=true;
q.push({nx,ny});
dis[nx][ny]=dis[x][y]+1;
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>g[i]+1;
}
bfs();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cout<<dis[i][j]<<" ";
}
cout<<endl;
}
}
魔板(最小步数)
每个字符串代表一个状态,给定初态和终态,字符串可以进行指定变换,求初态到终态的最小变换次数,且输出变换次序
#include<iostream>
#include<queue>
#include<map>
#include<algorithm>
#include<unordered_map>
using namespace std;
string res="";
unordered_map<string,int> dist;
unordered_map<string,pair<char,string> > pre;
char g[2][4];
void set(string s){
for(int i=0;i<4;i++)
g[0][i]=s[i];
for(int i=3,j=4;i>=0;i--,j++)
g[1][i]=s[j];
}
string get(){
string s="";
for(int i=0;i<4;i++)
s+=g[0][i];
for(int i=3;i>=0;i--)
s+=g[1][i];
return s;
}
string m1(string s){
set(s);
for(int i=0;i<4;i++) swap(g[0][i],g[1][i]);
return get();
}
string m2(string s){
set(s);
char a,b;
a=g[0][3],b=g[1][3];
for(int i=2;i>=0;i--)
g[0][i+1]=g[0][i],g[1][i+1]=g[1][i];
g[0][0]=a,g[1][0]=b;
return get();
}
string m3(string s){
set(s);
char a=g[0][1];
g[0][1]=g[1][1];
g[1][1]=g[1][2];
g[1][2]=g[0][2];
g[0][2]=a;
return get();
}
void bfs(string start,string end){
if(start==end) return;
queue<string> q;
q.push(start);
dist[start]=0;
while(!q.empty()){
string t=q.front();q.pop();
if(t==end) return;
string s[3];
s[0]=m1(t);
s[1]=m2(t);
s[2]=m3(t);
for(int i=0;i<3;i++){
string str=s[i];
if(dist.count(str)==0){
dist[str]=dist[t]+1;
pre[str]={char(i+'A'),t};
q.push(str);
}
}
}
}
int main(){
string start="12345678",end="";
for(int i=1;i<=8;i++){
char c;cin>>c;
end+=c;
}
bfs(start,end);
cout<<dist[end]<<endl;
while(end!=start){
res+=pre[end].first;
end=pre[end].second;
}
reverse(res.begin(),res.end());
if(res.size()) cout<<res;
}