广搜(练习4题)

几道例题还比较简单,练习就卡了比较长的时间了(。_。)

所以我会写一下解题思路了(๑ŐдŐ)
还有博客抽风所以代码里会有一些奇奇怪怪的东西,无视就好了qwq。

这几道题我就按各人认为的难易程度来排序吧QAQ。

第一题.

题意:输入一个迷宫,输出起点到终点的最短路径。


输入:

10
0100110100
0001110010
1000000001
1000100011
0000101100
1000001100
1001010011
0000010100
0101010000
1001000001
1 7 10 2

输出:

14


解题思路:就是走迷宫233。之前做过的了(⊙o⊙)。

(详见:http://blog.csdn.net/mr_wuyongcong/article/details/78732439 广搜例题


代码:

#include<cstdio>
using namespace std;
int n,head,tail,state[1000001][3],x,y,s,py,px;
bool walk[1001][1001];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};//移动方式
char c;
void bfs()
{
	state[1][2]=0;
	head=0;
	tail=1;
	do
	{
		head++;//出队
		for (int i=0;i<4;i++)
		{
			x=state[head][0]+dx[i];//位置
			y=state[head][1]+dy[i];//位置
			if (walk[x][y] && x>0 && y>0 && x<=n && y<=n)//是否可以通行
			{
				tail++;//入队
				state[tail][2]=state[head][2]+1;
				state[tail][0]=x;
				state[tail][1]=y;
				walk[x][y]=false;//封闭路线
				if (x==px && y==py)//判断终点
				{
					s=state[tail][2];
					return;
				}
			}
		}
	}
	while(head<tail);//判断结束
}
int main()
{
	scanf("%d\n",&n);
	for (int i=1;i<=n;i++)
	{
	  for (int j=1;j<=n;j++)
	  {
	  	c=getchar();
	  	if (c=='0') walk[i][j]=true;
	  }
	  c=getchar();
	}	
	scanf("%d%d%d%d",&state[1][0],&state[1][1],&px,&py);  
	//输入不解释
	bfs();//广搜不解释
	printf("%d",s);//输出不解释
	//就是那么任性QAQ
}


第二题:细胞问题(水题)

题目大意:一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。


输入:

4 10
0234500067
1034560500
2045600671
0000000089
输出:

4


解题思路:这道题刚开始做了半天从一个开始搜。后来突然顿悟,为什么不能从多个位置开始搜>(@_@)<。于是就轻轻松松的搞定了233。


代码:

#include<cstdio>
using namespace std;
int n,m,s,head,tail,state[2401][2];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};//细胞拓展方向
int a[61][61];
char c;
void bfs(int x,int y)
{
	head=0;
	tail=1;
	state[1][0]=x;
	state[1][1]=y;
	do
	{
		head++;//出队
		for (int i=0;i<4;i++)
		{
			x=state[head][0]+dx[i];
			y=state[head][1]+dy[i];
			if(a[x][y] && x>0 && x<=m && y>0 && y<=n)//如果这里是细胞则往这边拓展
			{
				tail++;//入队
				a[x][y]=false;//封闭该位置细胞
				state[tail][0]=x;
				state[tail][1]=y;
			}
		}
	}
	while (head<tail);
}
int main()
{
	scanf("%d%d\n",&m,&n);		
	for (int i=1;i<=m;i++)
	{
	  for (int j=1;j<=n;j++)
	  {
	  	c=getchar();
	  	if (c!='0') a[i][j]=true;
	  }
	  c=getchar();
	}
	//输入不解释  
	for (int i=1;i<=m;i++)
	  for (int j=1;j<=n;j++)//将所有的细胞枚举一遍
	  {
	  	if(a[i][j])//当该处有细胞时数量可以加了
	  	{
	  		bfs(i,j);//封闭该位置链接的细胞
	  		s++;//数量加1
	  	}
	  }
	printf("%d",s);//输出
}

第三题:最小转弯路径(难度开始加大了)

题意:给出一个地图,求起点到终点要转的最少弯数。


输入:

5 7
1 0 0 0 0 1 0
0 0 1 0 1 0 0  
0 0 0 0 1 0 1  
0 1 1 0 0 0 0  
0 0 0 0 1 1 0 
1 3 1 7 

输出:

5

附图:


解题思路:

最小转弯,不是最少步数。做法比较简单,不过是把拓展方式从4个方向一个格改成从4个方向撞到墙为止的一次性拓展完。(用老师的说法就是代价相同)

不过注意:封路和墙不要混为一谈。因为他是撞到墙才停止拓展,而碰到已经被走过的路只不过是不入队而不是不继续拓展。(被卡了好一会qAq)


贴代码时间:

#include<cstdio>
using namespace std;
int head,tail,n,m,state[10001][3],c,s,x,y,qx,qy;
bool ok[101][101],a[101][101];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};//拓展方向
void bfs()
{
	head=0;
	tail=1;
	do
	{
		head++;//出队
		for (int i=0;i<4;i++)//4个方向
		{
			x=state[head][0];y=state[head][1];
			int j=1;
			while (!a[x+dx[i]*j][y+dy[i]*j] && x+dx[i]*j<=n && y+dy[i]*j<=m && x+dx[i]*j>0 && y+dy[i]*j>0)
			//如果碰到墙或边缘就结束拓展
			{
			  if (!ok[x+dx[i]*j][y+dy[i]*j])
			  //如果已经走过的路线就不入队
			  {
			  	tail++;//入队
			  	state[tail][0]=x+dx[i]*j;
			  	state[tail][1]=y+dy[i]*j;//储存位置
			  	state[tail][2]=state[head][2]+1;//储存转弯数
			  	ok[x+dx[i]*j][y+dy[i]*j]=true;//已经走过该地
			  	if (x+dx[i]*j==qx && y+dy[i]*j==qy)//结束判断
			  	{
			  		s=state[tail][2];
			  		return;
			  	}
			  }
			  j++;//下一个拓展
			}
		}
	}
	while(head<tail);//空队退出
}
int main()
{
	scanf("%d%d\n",&n,&m);		
	for (int i=1;i<=n;i++)
	{
	  for (int j=1;j<=m;j++)
	  {
	  	scanf("%d",&c);
	  	if (c!=0) a[i][j]=true;
	  }
	}
	scanf("%d%d%d%d",&state[1][0],&state[1][1],&qx,&qy);
	//输入不解释
	bfs();//函数不解释
	printf("%d",s-1);//输出不解释
}

最后的压轴题:麻将游戏

在一种"麻将"游戏中,游戏是在一个有W*H格子的矩形平板上进行的。每个格子可以放置一个麻将牌,也可以不放(如图所示)。玩家的目标是将平板上的所有可通过一条路径相连的两张相同的麻将牌,从平板上移去。最后如果能将所有牌移出平板,则算过关。
  这个游戏中的一个关键问题是:两张牌之间是否可以被一条路径所连接,该路径满足以下两个特性:
  1. 它由若干条线段组成,每条线段要么是水平方向,要么是垂直方向。
  2. 这条路径不能横穿任何一个麻将牌 (但允许路径暂时离开平板)。
  这是一个例子:


  在(1,3)的牌和在(4, 4)的牌可以被连接。(2, 3)和(3, 4)不能被连接。
  你的任务是编一个程序,检测两张牌是否能被一条符合以上规定的路径所连接。 


输入:输入文件的第一行有两个整数w,h (1<=w,h<=75),表示平板的宽和高。接下来h行描述平板信息,每行包含w个字符,如果某格子有一张牌,则这个格子上有个'X',否则是一个空格。平板上最左上角格子的坐标为(1,1),最右下角格子的坐标为(w,h)。接下来的若干行,每行有四个数x1, y1, x2, y2 ,且满足1<=x1,x2<=w,1<=y1,y2<=h,表示两张牌的坐标(这两张牌的坐标总是不同的)。如果出现连续四个0,则表示输入结束。

5 4
XXXXX
X   X
XXX X
 XXX 
2 3 5 3
1 3 4 4
2 3 3 4
0 0 0 0


输出:

输出文件中,对于每一对牌输出占一行,为连接这一对牌的路径最少包含的线段数。如果不存在路径则输出0。

4

3

0


解题思路:这道题卡了挺久的,近5个小时才做出来。这道题一看就是第三题的升级版,只要注意可以走外围和每次把封路还原就Ok了o(>﹏<)o


终极代码时间:

#include<cstdio>
using namespace std;
int head,tail,state[5930][3],n,m,s,x1,x2,y1,y2;
bool a[77][77],walk[77][77];
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};//4个方向
char c;
void bfs(int x,int y,int px,int py)
//计算从(x,y)到(px,py)的最小转弯数
//这里不讲了,详见第3题
{
	head=0;
	tail=1;
	state[1][0]=x;
	state[1][1]=y;
	state[1][2]=0;
	do
	{
		head++;
		for (int i=0;i<4;i++)
		{
			x=state[head][0];y=state[head][1];
			int j=1;
			while (!a[x+dx[i]*j][y+dy[i]*j] && x+dx[i]*j<=n+1 && y+dy[i]*j<=m+1 && x+dx[i]*j>=0 && y+dy[i]*j>=0)
			{
			  if (!walk[x+dx[i]*j][y+dy[i]*j])
			  {
			  	tail++;
			  	state[tail][0]=x+dx[i]*j;
			  	state[tail][1]=y+dy[i]*j;
			  	state[tail][2]=state[head][2]+1;
			  	walk[x+dx[i]*j][y+dy[i]*j]=true;
			  	if (x+dx[i]*j==px && y+dy[i]*j==py)
			  	{
			  		s=state[tail][2];
			  		return;
			  	}
			  }
			  j++;
			}
		}
	}
	while(head<tail);
}
int main()
{
	scanf("%d%d",&m,&n);//输入,注意是反过来的
	c=getchar();//读第一行的换行符
	for (int i=1;i<=n;i++)
	{
	  int j=0;
	  while ((c=getchar())!='\n')
	  {
	  	j++;
	  	if (c=='X') a[i][j]=true;//处理可否通行
	  }
	}	
	x1=1;
	
	while (x1!=0 || y1!=0 || x2!=0 || y2!=0)//如果都为零就退出
	{
		scanf("%d%d%d%d",&y1,&x1,&y2,&x2);//输入,注意是反过来的
		if (x1!=0 && y1!=0 && x2!=0 && y2!=0)//如果都不为0
		{
			for (int i=0;i<=n+1;i++)
		  		for (int j=0;j<=m+1;j++) {walk[i][j]=false;}//还原封路
			s=0;//还原
			a[x2][y2]=false;//解掉终点的封锁
			bfs(x1,y1,x2,y2);//求
			a[x2][y2]=true;//打开终点的封锁
			printf("%d\n",s);
		}
	}
}


好了,广搜题目就那么多。↖(^ω^)↗

转载于:https://www.cnblogs.com/sslwyc/p/9218661.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值