1 广搜板子
int bfs(int sx,int sy)
{
q.push((Pos){sx,sy}); //起点加入队列
vis[sx][sy]=true; //标记
while(!q.empty())
{
x=q.front().x;
y=q.front().y; //获取起始坐标
q.pop(); //弹出队列
if(符合条件) return ans(答案);
for(int i=0;i<走法;i++)
{
tx=x+dx[i];
ty=y+dy[i];
if(符合条件) continue;
if(符合条件) continue; //符合条件跳过循环
/*
可行,执行该部分语句
*/
q.push((Pos){tx,ty}); //加入队列
}
}
}
2 迷宫最短路
1) 马走日走田问题
最短路问题一般选择广搜
1.一直在用cnt,cnt好像更经常用在深搜而不是广搜
2.因为广搜是同时走多条路,cnt会计算所有路致错
广搜
#include <iostream>
#include <queue>
#include <cstring>
#define pii pair<int,int>
using namespace std;
int x1,x2,y1,y2;
//int dx[]= {1,-1,1,-1,2,2,-2,-2};
//int dy[]= {2,2,-2,-2,2,-2,2,-2};
int dx[12]= {1,1,2,2,2,2,-1,-1,-2,-2,-2,-2};
int dy[12]= {-2,2,-2,-1,1,2,-2,2,-1,1,-2,2};
int d[25][25];
bool st[25][25];
void bfs(int x,int y)
{
queue<pii> q;
q.push({x,y});
memset(d,-1,sizeof d);
d[x][y]=0;
// st[x][y]=1;
while(q.size())
{
int a1=q.front().first;
int b1=q.front().second;
// cnt++;
//cnt更新逻辑有问题,广搜多条路同时进行,这样算了左上侧所有路
q.pop();
for(int i=0; i<12; i++ )
{
int a=a1+dx[i];
int b=b1+dy[i];
if(a<=0||b<=0||a>21||b>21||d[a][b]!=-1)continue;
d[a][b]=d[a1][b1]+1;
if(a==1&&b==1)
{
cout<< d[a][b]<<endl;
return ;
}//现在返回更好
q.push({a,b});
}
}
return ;
}
int main()
{
cin>>x1>>y1>>x2>>y2;
st[x1][y1]=1;
st[x2][y2]=1;
bfs(x1,y1);
bfs(x2,y2);
}
深搜解决最短路(特殊)
#include<bits/stdc++.h>
using namespace std;
int x,y,f[30][30];
//f[i][j]:从i,j走到1,1所需的最小步数
int dx[13]={0,-2,-2,+2,+2,-1,-1,+1,+1,-2,-2,+2,+2};
int dy[13]={0,-1,+1,-1,+1,-2,+2,-2,+2,-2,+2,-2,+2};
//马字8个方向,田字4个方向
void dfs(int x,int y,int step) //记忆化搜索,走到x,y花了step步
{
f[x][y]=step; //更新最小步数
for (int i=1;i<=12;i++) //12个方向走一遍
{
int xx=x+dx[i];
int yy=y+dy[i];
if (xx>=1&&xx<=20&&yy>=1&&yy<=20&&(f[xx][yy]==0||f[xx][yy]>step+1))
//重点是if条件里的可以被拓展f[xx][yy]>step+1
dfs(xx,yy,step+1);
//如果没超出边界并且xx,yy可以被更新,就继续走
}
}
int main()
{
for (int i=1;i<=2;i++)
{
scanf("%d%d",&x,&y);
memset(f,0,sizeof(f));
dfs(x,y,0); //走到x,y需要0步
printf("%d\n",f[1][1]); //最后输出
}
return 0;
}
2)迷宫找东西
特判失败,wa在 4,10.不会调。
调完是边界问题,边界不是最大2000,而应该写为m,n
代码
#include <iostream>
#include <queue>
#include <cstring>
#define pii pair<int,int>
#define int long long
using namespace std;
const int maxn=2010;
int st[maxn][maxn];
int dx[]= {0,0,1,-1};
int dy[]= {1,-1,0,0};
int n,m;
string g[maxn];
void bfs(int x,int y)
{
queue<pii> q;
memset(st,-1,sizeof st);
q.push({x,y});
st[x][y]=0;
while(q.size())
{
int a1=q.front().first;
int b1=q.front().second;
q.pop();
for(int i=0; i<4; i++ )
{
int a=a1+dx[i];
int b=b1+dy[i];
if(a<0||b<0||a>=n||b>=m)continue;
//边界是n,m 。
if(st[a][b]!=-1)continue;
if(g[a][b]=='#')continue;
st[a][b]=st[a1][b1]+1;
if(g[a][b]=='d')
{
cout<< st[a][b]<<endl;
return ;
}
q.push({a,b});
}
}
cout<<"No Way!"<<endl;
return;
}
signed main()
{
cin>>n>>m;
for(int i=0; i<n; i++)
cin>>g[i];
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
if(g[i][j]=='m')
{
bfs(i,j);
return 0 ;
}
}
}
// cout << "No Way!" << endl;没有找到m
return 0;
}
3)最长字符串接龙(不会)
3 洪水填充
细胞数量
必须先进行边界判断,数组才不会越界
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=110;
string s[110];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int st[maxn][maxn];
int cnt;
void dfs(int x,int y)
{
for(int i=0;i<4;i++)
{
int a=x+dx[i];
int b=y+dy[i];
if(a<0||a>=n||b<0||b>=m)continue;
//必须先进行边界判断否则会re
if(st[a][b]==1)continue;
if(s[a][b]=='0')continue;
/*在检查 s[a][b] 之前没有保证 a 和 b 在有效范围内。
如果 a 或 b 超出了有效范围,访问 s[a][b] 会导致越界访问,从而引发运行时错误*/
st[a][b]=1;
dfs(a,b);
}
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=0;i<n;i++)cin>>s[i];
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(st[i][j]==0&&s[i][j]!='0')//混用字符0和数字0致错
{
dfs(i,j);
// cout<<cnt<<endl;
cnt++;
}
}
}
cout<<cnt<<endl;
return 0;
}
4 多源BFS
1)血色先锋队
//在for里找pair,不能直接传入{a,b};
find(ve.begin(), ve.end(), make_pair(a, b)) != ve.end()
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,a,b;
const int maxn=510;
typedef pair<int,int> pii;
queue<pii> q;
int st[maxn][maxn];
int dx[]= {0,0,1,-1};
int dy[]= {1,-1,0,0};
void bfs()
{
while(!q.empty())
{
int x=q.front().first;
int y=q.front().second;
q.pop();
for(int i=0; i<4; i++)
{
int a=x+dx[i];
int b=y+dy[i];
if(a<=0||b<=0||a>n||b>m)continue;
if(st[a][b]!=-1)
continue;
q.push({a,b});
st[a][b]=st[x][y]+1;
// if (find(ve.begin(), ve.end(), make_pair(a, b)) != ve.end())
// {
// cout<<st[a][b]<<endl;
// 要按顺序输出 }
}
}
}
int main()
{
memset(st,-1,sizeof st);//要初始化为-1
cin>>n>>m>>a>>b;
while(a--)
{
int x,y;
cin>>x>>y;
st[x][y]=0;//因为先锋所在位置耗时0
q.push({x,y});
} bfs();
for(int i=1; i<=b; i++)
{
int x,y;
cin>>x>>y;
cout<<st[x][y]<<endl;
//边读入边输出,按顺序输出的处理方法
}
}
5 染色问题
1)
BFS
#include<bits/stdc++.h>
using namespace std;
int n,m;
char want[1005][1005],now[1005][1005];
int dx[8]= {0,0,1,1,-1,-1,1,-1};
int dy[8]= {1,-1,1,-1,1,-1,0,0};
bool vis[1005][1005];
bool cmp()
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if(want[i][j]!=now[i][j])return 0;
}
}
return 1;
}
void solve(int x,int y)
{
bool flag=0;
for(int k=0; k<=7; k++)
{
int mx=x+dx[k];
int my=y+dy[k];
if(mx<=0||mx>n||my<=0||my>m||want[mx][my]=='.')
{
flag=1;
break;
}
}
//第一块判断这个点是否染色
//第二块染色。 ps:我们不会再倒过来染色因为效果一样
for(int k=0; k<=7; k++)
{
int mx=x+dx[k];
int my=y+dy[k];
if(mx<=0||mx>n||my<=0||my>m||vis[mx][my])
{
continue;
}
if(!flag)
{
now[mx][my]='#';
}
vis[mx][my]=1;
solve(mx,my);
}
}
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
cin>>want[i][j];
now[i][j]='.';
}
}
solve(1,1);//随便从那个点开始都一样
string s=(cmp())?"YES":"NO";
cout<<s;
return 0;
}
枚举
#include<bits/stdc++.h>
using namespace std;
int n,m;
char want[1005][1005],now[1005][1005];
int dx[8]={0,0,1,1,-1,-1,1,-1};
int dy[8]={1,-1,1,-1,1,-1,0,0};//位移数组
bool cmp(){//比对
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(want[i][j]!=now[i][j])return 0;
}
}
return 1;
}
void solve(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
bool flag=0;
for(int k=0;k<=7;k++){
int mx=i+dx[k];
int my=j+dy[k];
if(mx<=0||mx>n||my<=0||my>m||want[mx][my]=='.'){
flag=1;//边界和当前点的状态要判断
break;
}
}
if(flag)continue;
for(int k=0;k<=7;k++){//染色
int mx=i+dx[k];
int my=j+dy[k];
now[mx][my]='#';
}
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>want[i][j];
now[i][j]='.';
}
}
solve();
string s=(cmp())?"YES":"NO";//三目运算符
/*
这里的三目运算符可以理解为:
if(cmp()==1)s="YES";
else s="NO";
但是三目更短,跑得也更快。
*/
cout<<s;
return 0;
}