ACM 预备队训练 广度优先搜索(BFS)

一.P1135 奇怪的电梯

思路:

        我们根据stl的队列的使用,我们可以利用它来进行二叉树的遍历,这就是广度搜索(BFS)的基础。而根据题目,每一次按按钮都有两种(当然,排除超出1-n范围的种类),故可以广度搜索每一种可能,直到到达终点。注意有排除前面已经走过的点,这样不仅可以加速,还可以保证求出的按键次数为最小的次数。

        具体 BFS 的代码说明见注释。

代码如下:

//广度优先搜索 BFS
#include<bits/stdc++.h>
using namespace std;
struct pos	    //结构体存储状态
{
	int lev,stp;
} ;
	queue<pos> qu;   //建立队列保存状态。
int a[202];
int vis[202]; //vis 保存是否已经搜索过了。 
int n,sta,end1; //sta 表示起点; end 表示终点。 
void bfs ()
{
	pos now,nex;
	now.lev=sta;
	now.stp=0;
//	queue<pos> qu;   //建立队列保存状态。 
	qu.push(now);
	vis[sta]=1;
	while (!qu.empty())    //开始遍历。 
	{
		now=qu.front();
		qu.pop();
		if (now.lev==end1)
		{
			cout<<now.stp;
			return ;
		}
		// 开始搜索;
		// 向上
		nex.lev=now.lev+a[now.lev]; 
		nex.stp=now.stp+1;
		if (nex.lev <= n && vis[nex.lev]==0)
		{
			vis[nex.lev]=1;
			qu.push(nex);
		}
		//向下
		nex.lev=now.lev-a[now.lev]; 
		nex.stp=now.stp+1;
		if (nex.lev >= 0 && vis[nex.lev]==0)
		{
			vis[nex.lev]=1;
			qu.push(nex);
		}
	}
	cout<<"-1";
	return ;
}
int main()
{
    cin>>n>>sta>>end1;
    for (int i=1;i<=n;i++) 
	{
		cin>>a[i];
		vis[i]=0;
	}
    bfs();
    return 0;
}

二.P1443 马的遍历

思路:

        本题还是bfs的思路,与上一题唯一不同的是马有8种走法,故每一次搜索有8种可能(即每一个父节点下有8个子节点,有8种路径)。所以我们可以用数组存储并加上for循环进行遍历所有路径。

        本题的重难点:①每一点都bfs的时候,注意vis的位置放置正确,保证重置为0 。②前往不要每一个点bfs一次,会TLE的,可以只bfs一次用vis保存每一点的次数。

代码如下:

#include<bits/stdc++.h>
using namespace std;
struct pos	    
{
	int x,y,step;
};
int dx[8]={-2,-2,2,2,1,-1,1,-1};
int dy[8]={-1,1,-1,1,2,-2,-2,2};
int n,m,sx,sy;  
int vis[405][405];
void bfs (int ex,int ey)
{
	queue <pos> qu;
    pos now,nex;
	now.x=sx;
	now.y=sy;
	now.step=0; 
	qu.push(now);
	vis[sx][sy]=now.step;
	while (!qu.empty())    //开始遍历。 
	{
		now=qu.front();
		qu.pop();
		/*if (now.x==ex && now.y==ey)
		{
			cout<<now.step;
			return ;
		}*/
		// 开始搜索;
		for (int k=0;k<8;k++)
		{
		nex.x=now.x+dx[k]; 
		nex.y=now.y+dy[k];
		nex.step=now.step+1;
		if (nex.x <= n && nex.x >=1 && nex.y <= m && nex.y >=1 && vis[nex.x][nex.y]==-1)
		{
			vis[nex.x][nex.y]=nex.step;
			qu.push(nex);	
		}
		}
	}
	//cout<<-1;
	return ;
}
int main()
{
    cin>>n>>m>>sx>>sy;
    for (int i=1;i<=n;i++)
    	for (int j=1;j<=m;j++)
    		vis[i][j]=-1;
    bfs(1,1);
    for (int i=1;i<=n;i++)
    {
    	for (int j=1;j<=m;j++)
    {
    	/*if (i==sx && j==sy) cout<<0;
    	else if (vis[i][j]) cout<<vis[i][j];
    	else bfs(i,j);*/
    	cout<<vis[i][j];
    	cout<<" ";
	}
		cout<<"\n";
	}
	return 0;
}

三.P3958 [NOIP2017 提高组] 奶酪

思路:

        本题题目复杂,但在本蒟蒻看来并不太难,与上面bfs的思路相同。

        注意:这题有个新手容易入的坑,就是cout<<"No"<<endl;将endl去掉,这是在测试的时候看似没问题(如下),但根据oj的测评方式会WA的!!!

3 
2 4 1 
0 0 1 
0 0 3 
YES 2 5 1 
0 0 1 
0 0 4 
NO 2 5 2 
0 0 2 
2 0 4
YES

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1005;
ll  r,n,h;
ll x[maxn],y[maxn],z[maxn];
struct pos
{
	ll x,y,z,height;
};
void bfs()
{
    cin>>n>>h>>r;
    for (int i=0;i<n;i++) cin>>x[i]>>y[i]>>z[i];
    for (int i=0;i<n;i++)  
    	if (z[i]<=r)
    	{
			bool vis[maxn];
			for (int k=0;k<n;k++) vis[k]=0;
    		pos now,next;
    		now.x=x[i]; now.y=y[i]; now.z=z[i],now.height=z[i]+r;
    		queue <pos> q;
    		q.push(now);
    		vis[i]=1;
    		while (!q.empty())
    		{
    			now=q.front();
    			q.pop();
    			if (now.height >= h)
    			{
    				cout<<"Yes"<<endl;
    				return ;
				}
				for (int j=0;j<n;j++)
				if (j!=i and vis[j]==0)
				{
					double dis=pow(now.x-x[j],2)+pow(now.y-y[j],2)+pow(now.z-z[j],2);
					//if (!f(now.x,now.y,now.z,x[j],y[j],z[j])) continue;
					if (dis <= 4*r*r)
					{
					next.x=x[j]; next.y=y[j]; next.z=z[j];
					next.height= z[j]+r;
					q.push(next);	
					vis[j]=1;
					}
				}
			}
		}
    cout<<"No"<<endl;
    return ;
}

int main()
{
	int www;
	cin>>www;
	while(www--)
	{
	bfs();
}
    return 0;
}

四.P1162 填涂颜色

思路:

        bfs + 反射(反过来,搜索外层)(染色)。 将非1的全改为2,从外面搜索,见2改为0 。

        本题要注意:注意dfs中的if语句,我在最外面多加了一圈0,这样子就相当于把外圈所有的0都连通起来,四面八方所有的0都可以被搜到,只会留下中间的1。 

代码如下:

#include<bits/stdc++.h>
using namespace std;
struct pos
{
	int x,y;
};
const int xx[4]={1,-1,0,0};
const int yy[4]={0,0,1,-1};
int n,a[35][35],b[35][35];
int main()
{
    for(int i=0;i<35;i++)
		for(int j=0;j<35;j++)
			a[i][j]=2;
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			int tmd;
			cin>>tmd;
			if(tmd==1)a[i][j]=1;
		}
	}
    //bfs:
    queue<pos> q;
    pos now,next;
    now.x=0;
    now.y=0;
    q.push(now);
    
    while (q.size())
    {
    	now=q.front();
    	q.pop();
    	for (int i=0;i<4;i++)
    	{
    		next.x=now.x+xx[i];
    		next.y=now.y+yy[i];
    		if (next.x>=0 and next.x<=n+1 and next.y>=0 and next.y<=n+1 and a[next.x][next.y]==2)
    		{
    			a[next.x][next.y]=0;
    			q.push(next);
			}
		}
	}
    for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cout<<a[i][j]<<" ";
		}
		if(i!=n)cout<<endl;
	}
    return 0;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值