DFS + BFS + 洛谷题

DFS

经典的迷宫问题( 回溯 问题 )

在起点处有四个方向,上下左右,

在这里插入图片描述走到终点之后,要再返回,看有没有其他更短的路径。

回溯过程,退回之后,要标记该点的值为没有访问过。

在这里插入图片描述直到找到最短的路径。

左右试探的图解
位置变化
在这里插入图片描述

以下是未经优化的代码。(dfs)

#include <iostream>
#include <unordered_map>
using namespace std;
int p, q;  //终点坐标,(P,q)
int a[100][100]; //1表示空地, 2 表示障碍物
int v[100][100];  //0 默认未访问, 1表示访问
int Min=99999;
void dfs(int x, int y, int step)  //x,y表示当前位置
{
	if (x == p && y == q)
	{
		if (step < Min)
			Min = step;
		return;
	}
	//这里默认顺时针试探,右下左上
	//只往右走
	if (a[x][y + 1] == 1 && v[x][y + 1] == 0)
	{
		v[x][y + 1] = 1;   //走到(x,y+1)这个点,并且做标记,表示走过。
		dfs(x, y + 1, step + 1);   //进入下一步,同样的操作
		v[x][y + 1] = 0;//回退出来,把原来的点标为未走过
	}
	//如果右边堵住了,则往下走
	if (a[x+1][y] == 1 && v[x][y + 1] == 0)
	{
		v[x][y + 1] = 1;
		dfs(x+1, y , step + 1);
		v[x][y + 1] = 0;
	}
	//向左走
	if (a[x ][y-1] == 1 && v[x][y - 1] == 0)
	{
		v[x][y - 1] = 1;
		dfs(x , y-1, step + 1);
		v[x][y - 1] = 0;
	}
	//上
	if (a[x-1][y ] == 1 && v[x - 1][y] == 0)
	{
		v[x - 1][y ] = 1;
		dfs(x - 1, y , step + 1);
		v[x - 1][y ] = 0;
	}
	return;
}

int main()
{
	int startx, starty;
	int n = 0, m=0; //m行,n列
	cin >> m >> n;
	for (int i = 1; i <= m; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			cin >> a[i][j];//1表示空地, 2 表示障碍物
		}
	}
	cin >> startx >> starty >> p >> q;
	v[startx][starty] = 1;
	dfs(startx, starty, 0);

	cout << Min;
	return 0;
}

/*
5 4
1  1 2 1
1  1 1 1
1 1 2 1
1 2 1 1
1 1 1 2
1 1 4 3


*/

其实可以定义一个方向数组
在这里插入图片描述
代码优化之后:

#include <iostream>
#include <unordered_map>
using namespace std;
int p, q;  //终点坐标,(P,q)
int a[100][100]; //1表示空地, 2 表示障碍物
int v[100][100];  //0 默认未访问, 1表示访问
int Min=99999;
//使用方向数组
int dx[4] = { 0,1,0,-1 };   
int dy[4] = { 1,0,-1,0 };

void dfs(int x, int y, int step)  //x,y表示当前位置
{
	if (x == p && y == q)
	{
		if (step < Min)
			Min = step;
		return;
	}
	for (int k = 0; k <= 3; k++)  //有四个方向,所以k有4个取值
	{
		int tx ,ty ;
		tx = x + dx[k];
		ty = y + dy[k];
		if (a[tx][ty] == 1 && v[tx][ty] == 0)  //四个方向,只要没有障碍,且没有走过,就可以继续走
		{
			v[tx][ty] = 1;
			dfs(tx, ty, step + 1);
			v[tx][ty] = 0;
		}
	}
	return;
}

int main()
{
	int startx, starty;
	int n = 0, m=0; //m行,n列
	cin >> m >> n;
	for (int i = 1; i <= m; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			cin >> a[i][j];//1表示空地, 2 表示障碍物
		}
	}
	cin >> startx >> starty >> p >> q;
	v[startx][starty] = 1;
	dfs(startx, starty, 0);
	cout << Min;
	return 0;
}

/*
5 4
1  1 2 1
1  1 1 1
1 1 2 1
1 2 1 1
1 1 1 2
1 1 4 3
*/

BFS

在这里插入图片描述在这里插入图片描述
在这里插入图片描述开始是位置(1,1)走的步数是0,
第二步走到(1,2) 走的步数是1
第二步也可以到(2,1 ) 走的步数是1


(拓展完毕之后可以出队)


在这里插入图片描述
进入两个点(能一步到达的位置),之后把第一个点出队
在这里插入图片描述
然后往下找,一旦入队所有一步能到达的点,则需要出队一个。
在这里插入图片描述在这里插入图片描述出队前,要保证该点下一步能到达的点入队。
不能拓展的,直接出队即可
关于头文件的使用
在这里插入图片描述(4)empty()

empty()检测是否为空,返回true则为空,返回false则非空,时间复杂度O(1)。

程序代码:

#include<cstdio> 
#include<queue>
using namespace std;
int main(){
	queue<int> q;
	printf("%d\n",q.empty());//先开始没有元素,为空(true);输出 1 
	for(int i=1;i<=5;i++) {
		q.push(i);		//push(i)用以将i压入队列,因此一次入队 1 2 3 4 5 
	}
	printf("%d\n",q.empty());//压入元素,为非看(false);输出 0
	return 0; 
}

运行结果:

(5)size()

size()返回queue内元素的个数,时间复杂度为O(1)。

程序代码:

#include<cstdio> 
#include<queue>
using namespace std;
int main(){
	queue<int> q;
	for(int i=1;i<=5;i++) {
		q.push(i);		//push(i)用以将i压入队列,因此一次入队 1 2 3 4 5 
	}
	printf("%d\n",q.size());// 输出队列元素个数 
	return 0; 
}

下面是代码实现

#include <iostream>
#include<queue>
using namespace std;
int p, q;  //终点坐标,(P,q)
int a[100][100]; //1表示空地, 2 表示障碍物
int v[100][100];  //0 默认未访问, 1表示访问

//四个方向
int dx[4] = {0, 1, 0, -1};     //四个方向, 右 下 左 上
int dy[4] = {1, 0, -1, 0};

//需要一个结构体,存该点的位置(x,y), 并且设置步数。
struct point
{
	int x;
	int y;
	int step;
};

queue<point> r;  //申请队列


/*void dfs(int x, int y, int step)  //x,y表示当前位置
{
	if (x == p && y == q)
	{
		if (step < Min)
			Min = step;
		return;
	}
	for (int k = 0; k <= 3; k++)  //有四个方向,所以k有4个取值
	{
		int tx ,ty ;
		tx = x + dx[k];
		ty = y + dy[k];
		if (a[tx][ty] == 1 && v[tx][ty] == 0)  //四个方向,只要没有障碍,且没有走过,就可以继续走
		{
			v[tx][ty] = 1;
			dfs(tx, ty, step + 1);
			v[tx][ty] = 0;
		}
	}
	return;
}
*/

int main()
{
	int startx=0, starty=0;
	int n = 0, m=0; //m行,n列
	int flag = 0;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)//输入
	{
		for (int j = 1; j <= m; j++)
		{
			cin >> a[i][j];
		}
	}
	cin >> startx >> starty >> p >> q;
	//BFS
	point start;  //起点
	start.x = startx;
	start.y = starty;

	start.step=0;
	r.push(start); //将起点入队
	v[startx][starty] =1 ;  //表示有走过
	while (!r.empty())//在队列不为空的时候
	{
		int x = r.front().x,y= r.front().y; //取队首的元素。
		if (x == p && y == q)
		{
			flag = 1;
			cout << r.front().step;
			break;
		}
		for (int k = 0; k <= 3; k++)
		{
			int tx, ty;
			tx = x + dx[k];
			ty = y + dy[k];
			if (a[tx][ty] == 1 && v[tx][ty] == 0)  //空地,且未访问
			{
				// 入队
				point temp;
				temp.x = tx;
				temp.y = ty;
				temp.step = r.front().step + 1; //   到新的点之后就可以步数多1 
				r.push(temp);
				v[tx][ty] = 1; //入队则已访问,设置为1
			}
		}
		r.pop();//将队首元素出队。
	}

	if (flag == 0)  cout << "no";
	else
		cout << "yes";

	return 0;
}

/*
5 4 
1 1 2 1
1 1 1 1
1 1 2 1
1 2 1 1
1 1 1 2
1 1 4 3
*/

1003 Crashing Balloon

On every June 1st, the Children’s Day, there will be a game named “crashing balloon” on TV. The rule is very simple. On the ground there are 100 labeled balloons, with the numbers 1 to 100. After the referee shouts “Let’s go!” the two players, who each starts with a score of “1”, race to crash the balloons by their feet and, at the same time, multiply their scores by the numbers written on the balloons they crash. After a minute, the little audiences are allowed to take the remaining balloons away, and each contestant reports his\her score, the product of the numbers on the balloons he\she’s crashed. The unofficial winner is the player who announced the highest score.

Inevitably, though, disputes arise, and so the official winner is not determined until the disputes are resolved. The player who claims the lower score is entitled to challenge his\her opponent’s score. The player with the lower score is presumed to have told the truth, because if he\she were to lie about his\her score, he\she would surely come up with a bigger better lie. The challenge is upheld if the player with the higher score has a score that cannot be achieved with balloons not crashed by the challenging player. So, if the challenge is successful, the player claiming the lower score wins.

So, for example, if one player claims 343 points and the other claims 49, then clearly the first player is lying; the only way to score 343 is by crashing balloons labeled 7 and 49, and the only way to score 49 is by crashing a balloon labeled 49. Since each of two scores requires crashing the balloon labeled 49, the one claiming 343 points is presumed to be lying.

On the other hand, if one player claims 162 points and the other claims 81, it is possible for both to be telling the truth (e.g. one crashes balloons 2, 3 and 27, while the other crashes balloon 81), so the challenge would not be upheld.

By the way, if the challenger made a mistake on calculating his/her score, then the challenge would not be upheld. For example, if one player claims 10001 points and the other claims 10003, then clearly none of them are telling the truth. In this case, the challenge would not be upheld.

Unfortunately, anyone who is willing to referee a game of crashing balloon is likely to get over-excited in the hot atmosphere that he\she could not reasonably be expected to perform the intricate calculations that refereeing requires. Hence the need for you, sober programmer, to provide a software solution.

Input
Pairs of unequal, positive numbers, with each pair on a single line, that are claimed scores from a game of crashing balloon.
Output
Numbers, one to a line, that are the winning scores, assuming that the player with the lower score always challenges the outcome.
Sample Input
343 49
3599 610
62 36

Sample Output
49
610
62

#include <stdio.h>
int flagA,flagB;
int result ;
void dfs(int m,int n,int kk)    //运用了深度优先的搜索策略
{
    int k =kk;
    if(m==1 && n==1)    
    {
       flagA=1; 
       return ;
    }
    if(n==1)
    flagB =1;   
    while( (k <  m || k <  n) && (k< 100) )
    {
       k++;
       if(m%k==0)
       {
            dfs(m/k,n,k);
            if(flagA)
                return;
       }
       if(n%k==0 )
       {
            dfs(m,n/k,k);
            if(flagA)
            return;
       }
    }
}

int main()
{
    int A,B,t;
    while(scanf("%d%d",&A,&B)!=EOF) 
    {
    	if(A<B)
    	{
    		t=A;
    		A=B;
    		B=t;
		}
		flagA=0;
		flagB=0;
		dfs(A,B,1);
		result=A;
		if(flagA==0 && flagB==1)
		{
			result=B;
		}
		printf("%d\n",result);
	}
    return 0;
}

P1363 幻象迷宫

在这里插入图片描述在这里插入图片描述

这里数据量注意最大是1500 开数组的时候1501也够了

思路: 找到初始地图的某点,存在无限大地图中的一点求模后和该点一致,说明能从该点出发又回到该点,则此时表明它 可以走无限远。所以关键是判断能不能第二次经过该点。

这里用dfs来做

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
//只要能访问第二遍,则走无穷远
const int MAXN = 1500 + 1;
const int dx[4] = {1, -1, 0, 0};
const int dy[4] = {0, 0, 1, -1};

int n, m;
int st_x, st_y;
int vis[MAXN][MAXN][3];
bool fl, a[MAXN][MAXN];
char ch;

void dfs(int x, int y, int lx, int ly) {
	if(fl) return;
	if(vis[x][y][0] && (vis[x][y][1]!=lx || vis[x][y][2]!=ly)) //未访问过的,且第二遍经过则成立
	{
		fl = 1;
		return;
	}
	vis[x][y][1] = lx, vis[x][y][2] = ly, vis[x][y][0] = 1;//记录下第一遍的访问点的下标 
	for(int i=0; i<4; ++i) {
		int xx = (x + dx[i] + n) % n, yy = (y + dy[i] + m) % m;//保证不会数组越界 
		int lxx = lx + dx[i], lyy = ly + dy[i];
		if(!a[xx][yy])  //有路可走 
		 {
			if(vis[xx][yy][1]!=lxx || vis[xx][yy][2]!=lyy || !vis[xx][yy][0])
			//(xx,yy)必须是没访问过的结点。 !vis[xx][yy][0]指的是不能重复走这个地图的点,需要走到扩展其他地图上 
				dfs(xx, yy, lxx, lyy);
		}
	}
}
int main() {
	ios::sync_with_stdio(false);
	while(cin >> n >> m) {
		fl = 0;
		memset(a, 0, sizeof(a));
		memset(vis, 0, sizeof(vis));
		for(int i=0; i<n; ++i)
			for(int j=0; j<m; ++j) {
				cin >> ch;
				if(ch == '#') a[i][j] = 1;
				if(ch == 'S') st_x = i, st_y = j;
			}
		dfs(st_x, st_y, st_x, st_y);
		if(fl) puts("Yes");
		else puts("No");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值