BFS解决最少步数模型问题

本文介绍了如何利用宽度优先搜索(BFS)解决两类问题:八数码游戏和寻找两个整数之间最短转换路径。在八数码游戏中,通过建立状态节点和操作边,实现BFS找到目标状态的最小步数。而在抓住那头牛的问题中,同样运用BFS寻找从起点到终点的最短路径。这两个实例展示了BFS在路径搜索问题中的应用。
摘要由CSDN通过智能技术生成

前置知识:BFS(宽度优先搜索)_如何何何的博客-CSDN博客

给定一个初始集合与一些操作,可以对该集合执行给定的操作,要求将集合变换成目标集合,求最少的操作次数。

将集合的每种状态看做点,每种操作看做一条边,即可将此类问题抽象为求解两点间的最短路径,且每条边的权值都为 1 ,可用宽度优先搜索解决。

例题1.八数码

845. 八数码 - AcWing题库

将网格看做点,对起点进行宽度优先搜索查找终点即可;

网格可用 string 存储;

由于网格只有九个点,交换操作数量较少,可用记录所有操作,搜索时枚举所有情况即可。

AC代码如下:

#include<iostream>
#include<cstring>
#include<unordered_map>
#include<queue>
#include<vector>
using namespace std;
const int N=10;
unordered_map<string,int>d;//每个状态的步数
vector<int>v[N];
string E=" 12345678x";


int bfs(string S){
    if(S==E)return 0;
	queue<string>q;
	q.push(S);
	d[S]=0;
	
	while(q.size()){ 
		string t=q.front();//取队头 
		q.pop();//删队头 
		
		//查找x的位置 
		int x=-1; 
		for(int i=1;i<=9;i++) 
			if(t[i]=='x')x=i;
			
		//操作当前状态 
		for(int i=0;i<v[x].size();i++){
			string k=t;
			char c=k[x];k[x]=k[v[x][i]];k[v[x][i]]=c;//交换操作
			if(k==E)return d[t]+1;//如果达到目标状态
			//如果该状态还没搜到 
			if(!d.count(k)){
				d[k]=d[t]+1;
				q.push(k); 
			}
		}	
	}
	return -1;
	
} 

int main(){
	//打表每个点的交换位置
	v[1].push_back(2),v[1].push_back(4); 
	v[2].push_back(1),v[2].push_back(3),v[2].push_back(5); 
	v[3].push_back(2),v[3].push_back(6); 
	v[4].push_back(1),v[4].push_back(5),v[4].push_back(7); 
	v[5].push_back(2),v[5].push_back(4),v[5].push_back(6),v[5].push_back(8);
	v[6].push_back(3),v[6].push_back(5),v[6].push_back(9); 
	v[7].push_back(4),v[7].push_back(8); 
	v[8].push_back(5),v[8].push_back(7),v[8].push_back(9); 
	v[9].push_back(6),v[9].push_back(8); 
		
	//输入初始状态 
	string S=" ";//下标从1开始i 
	for(int i=0;i<9;i++){
		char c;
		cin>>c;
		S+=c;
	}
	
	cout<<bfs(S);
	return 0;
}

例题2:抓住那头牛

抓住那头牛 - C语言网 (dotcpp.com)

AC代码如下:

#include<iostream>
#include<queue>
#include<cmath>
using namespace std;
const int N = 1e5 + 10;
int s, e;
int t[N];//到每个点用的时间
bool st[2 * N];
int l, r;//给定两个大致范围防止爆栈

int bfs() {
    if (s == e)return 0;
    queue<int>q;
    q.push(s);
    st[s] = true;

    while (q.size()) {
        int tmp = q.front();
        q.pop();
        int a = tmp + 1, b = tmp - 1, c = tmp * 2;

        if (a > l && a < r && !st[a]) { st[a] = true; t[a] = t[tmp] + 1; q.push(a); if (a == e)return t[a]; }
        if (b > l && b < r && !st[b]) { st[b] = true; t[b] = t[tmp] + 1; q.push(b); if (b == e)return t[b]; }
        if (c > l && c < r && !st[c]) { st[c] = true; t[c] = t[tmp] + 1; q.push(c); if (c == e)return t[c]; }
    }
    return -1;
}

int main() {
    cin >> s >> e;
    l = -1, r = N;
    cout << bfs();
    return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值