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;
}
posted on 2024-08-13 10:13  Hoshino1  阅读(4)  评论(0编辑  收藏  举报