ACM宽度优先搜索BFS

预备知识

队列

先进先出(FIFO),队头删除元素,队尾加入元素。

二叉树“层次遍历”

从上到下、从左到右的顺序进行遍历。

使用算法实现思想

        建立一个队列用于存放节点的信息。当访问到一个节点时(队列不空时),先访问该节点,再将该节点的左右儿子放入队列。再根据这个队列依次从前向后访问。(搜索的本质就是暴力枚举

本质上就是描述出:起始状态、目标状态以及状态转移规则!

经典例题

奇怪的电梯

        :使用楼层的层次遍历(根据每一层楼的树状结构可以形成一个树状结构),同时使用一个数组来标记一个楼层是否曾经到达过(用来优化剪枝)),当到达目标楼层后就停止迭代。(使用楼层以及跳转次数作为一个特定的状态

#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;

int N, k[201], visit[201], start, target, decision;
struct position
{
	int level;
	int steps;
};

int main()
{
	while(scanf("%d", &N), N)
	{
		decision = 0;
		scanf("%d%d", &start, &target);
		memset(k, 0, sizeof(k));
		memset(visit, 0, sizeof(visit));
		for(int i = 1; i <= N; i++)
			scanf("%d", &k[i]);
		//BFS
		position cur, next;
		cur.level = start;
		cur.steps = 0;
		queue<position> Q;
		Q.push(cur);
		visit[start] = 1;
		while(!Q.empty())
		{
			cur = Q.front();
			Q.pop();
			if(cur.level == target)
			{
				printf("%d\n", cur.steps);
				decision = 1;
				break;
			}
			next.level = cur.level + k[cur.level];
			next.steps = cur.steps + 1;
			if(next.level <= N)
				if(visit[next.level] == 0)
				{
					visit[next.level] = 1;
					Q.push(next);
				}
			next.level = cur.level - k[cur.level];
			next.steps = cur.steps + 1;
			if(next.level >= 1)
				if(visit[next.level] == 0)
				{
					visit[next.level] = 1;
					Q.push(next);
				}
		} 
		if(decision == 0) printf("-1\n");
	}
	return 0;
}

非常可乐

        :把状态定义为三个杯子中的可乐量以及步骤数,同时使用一个三维数组做标记(也可以使用二维),一直迭代到目标状态。

#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;

int s, n, m, visit[102][102][102], decision;
bool isSatisfied(double x, double y, double z) { return (x == y && z == 0) || (x == z && y == 0) || (z == y && x == 0); }
struct state
{
	int cola1;
	int cola2;
	int cola3;
	int steps;
};

int main()
{
	while(scanf("%d%d%d", &s, &n, &m), s)
	{
		decision = 0;
		memset(visit, 0, sizeof(visit));
		state cur, next;
		cur.cola1 = s;
		cur.cola2 = 0;
		cur.cola3 = 0;
		cur.steps = 0;
		visit[s][0][0] = 1;
		queue<state> que;
		que.push(cur);
		while(!que.empty())
		{
			cur = que.front();
			que.pop();
			if(isSatisfied(cur.cola1, cur.cola2, cur.cola3))
			{
				decision = 1;
				printf("%d\n", cur.steps);
				break;
			}
			// 1 -> 2
			if(cur.cola1 >= n-cur.cola2)
			{
				next.cola1 = cur.cola1 - (n - cur.cola2);
				next.cola2 = n;
				next.cola3 = cur.cola3;
			}
			else
			{
				next.cola1 = 0;
				next.cola2 = cur.cola1 + cur.cola2;
				next.cola3 = cur.cola3;
			}
			if(visit[next.cola1][next.cola2][next.cola3] == 0)
			{
				visit[next.cola1][next.cola2][next.cola3] = 1;
				next.steps = cur.steps + 1;
				que.push(next);
			}
			// 1 -> 3
			if(cur.cola1 >= m-cur.cola3)
			{
				next.cola1 = cur.cola1 - (m - cur.cola3);
				next.cola3 = m;
				next.cola2 = cur.cola2;
			}
			else
			{
				next.cola1 = 0;
				next.cola3 = cur.cola1 + cur.cola3;
				next.cola2 = cur.cola2;
			}
			if(visit[next.cola1][next.cola2][next.cola3] == 0)
			{
				visit[next.cola1][next.cola2][next.cola3] = 1;
				next.steps = cur.steps + 1;
				que.push(next);
			}
			// 2 -> 1
			if(cur.cola2 >= s-cur.cola1)
			{
				next.cola2 = cur.cola2 - (s - cur.cola1);
				next.cola1 = s;
				next.cola3 = cur.cola3;
			}
			else
			{
				next.cola2 = 0;
				next.cola1 = cur.cola2 + cur.cola1;
				next.cola3 = cur.cola3;
			}
			if(visit[next.cola1][next.cola2][next.cola3] == 0)
			{
				visit[next.cola1][next.cola2][next.cola3] = 1;
				next.steps = cur.steps + 1;
				que.push(next);
			}
			// 2 -> 3
			if(cur.cola2 >= m-cur.cola3)
			{
				next.cola2 = cur.cola2 - (m - cur.cola3);
				next.cola3 = m;
				next.cola1 = cur.cola1;
			}
			else
			{
				next.cola2 = 0;
				next.cola3 = cur.cola2 + cur.cola3;
				next.cola1 = cur.cola1;
			}
			if(visit[next.cola1][next.cola2][next.cola3] == 0)
			{
				visit[next.cola1][next.cola2][next.cola3] = 1;
				next.steps = cur.steps + 1;
				que.push(next);
			}
			// 3 -> 1
			if(cur.cola3 >= s-cur.cola1)
			{
				next.cola3 = cur.cola3 - (s - cur.cola1);
				next.cola1 = s;
				next.cola2 = cur.cola2;
			}
			else
			{
				next.cola3 = 0;
				next.cola1 = cur.cola3 + cur.cola1;
				next.cola2 = cur.cola2;
			}
			if(visit[next.cola1][next.cola2][next.cola3] == 0)
			{
				visit[next.cola1][next.cola2][next.cola3] = 1;
				next.steps = cur.steps + 1;
				que.push(next);
			}
			// 3 -> 2
			if(cur.cola3 >= n-cur.cola2)
			{
				next.cola3 = cur.cola3 - (n - cur.cola2);
				next.cola2 = n;
				next.cola1 = cur.cola1;
			}
			else
			{
				next.cola3 = 0;
				next.cola2 = cur.cola3 + cur.cola2;
				next.cola1 = cur.cola1;
			}
			if(visit[next.cola1][next.cola2][next.cola3] == 0)
			{
				visit[next.cola1][next.cola2][next.cola3] = 1;
				next.steps = cur.steps + 1;
				que.push(next);
			}
		}
		if(decision == 0) printf("NO\n");
	}
	return 0;
}

骑士移动问题

        :BFS的同时使用一个数组来描述骑士一步可以走到的地方,这样就可以使用一层循环来访问所有骑士从一个点到另一个点的可能。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;

//int defaul = 0;
int n1, n2, visit[8][8];
int moves[8][2] = {{1,2}, {1,-2}, {2,1}, {2,-1}, {-1,2}, {-1,-2}, {-2,1}, {-2,-1}};
char m1, m2;
struct state
{
	int row;
	int col;
	int steps;
};

int main()
{
	while(~scanf("%c%d %c%d", &m1, &n1, &m2, &n2))
	{
		getchar();	//注意还有一个换行符!
		memset(visit, 0, sizeof(visit));
		state start, target;
		start.row = (int)(m1 - 'a');
		start.col = n1 - 1;
		start.steps = 0;
		target.row = (int)(m2 - 'a');
		target.col = n2 - 1;
		visit[start.row][start.col] = 1;
		//cout << "DEFAULT:" << start.row << start.col << " " << target.row << target.col << endl;
		state cur, next;
		cur = start;
		queue<state> que;
		que.push(cur);
		while(!que.empty())
		{
			cur = que.front();
			//cout << "DEFAULT(father):" << cur.row+1 << cur.col+1 << endl;
			que.pop();
			if(cur.row == target.row && cur.col == target.col)
			{
				printf("To get from %c%d to %c%d takes %d knight moves.\n", m1, n1, m2, n2, cur.steps);
				break;
			}
			for(int i = 0; i < 8; i++)
			{
				next.row = cur.row + moves[i][0];
				next.col = cur.col + moves[i][1];
				if((next.row < 8) && (next.col < 8) && (next.row >= 0) && (next.col >= 0) && (visit[next.row][next.col] == 0)) 
				{
					next.steps = cur.steps + 1;
					visit[next.row][next.col] = 1;
					que.push(next);
					//defaul++;
					//cout << "DEFAULT:" << next.row+1 << next.col+1 << " " << next.steps << endl;
				}
			}
		}
		//cout << "DEFAULT:" << defaul << endl;
	}
	return 0;
}
  • 18
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值