回溯法和路径寻找

之前学的不踏实,感觉程序写的毛毛躁躁,现在正好趁暑假把系统的再把有些知识点过一遍,加固一下

目录

回溯法

路径寻找:


这个是我自己对回溯法的理解;

关于回溯法自己的理解 - 小志61314 - 博客园 (cnblogs.com)

回溯法的最基本的问题就是n皇后了,我看了好多题,其实本质与n皇后差不多

两种搜索方式:搜索方式一定要明白

第一种是最基本的全排列,枚举行,对列进行全排列,与此同时兼顾一下对角线

说到这里,感觉代码呼之欲出了

虽然表面上说是全排列,本质依然是搜索树的形式,依次的把皇后放进去,然后行是层数,每一层也就是每一行,皇后可以放在不同的列上,还要判断一下对角线,如果不行就回溯到上一层(不要忘记清空数组),进行那一层其他的选择,这就是回溯法,会有一组或者多组的合法解或者最优解,与下面的路径寻找是不一样的,路径寻找是找到一个从初始状态到终止状态的路径

#include<iostream>
using namespace std;
const int N=20;
bool row[N],col[N],dg[N],udg[N];
int n;
char g[N][N];
void dfs(int u)
{
	if(u==n)
	{
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<n;j++)
				cout<<g[i][j];
			cout<<"\n";
		}
	}
	for(int i=0;i<n;i++)
	{
		if(!col[i]&&!dg[u+i]&&!udg[n-u+i])
		{
			g[u][i]='Q';
			col[i]=dg[u+i]=udg[n-u+i]=true;
			dfs(u+1);
			col[i]=dg[u+i]=udg[n-u+i]=false;
			g[u][i]='.';
		}
	}
}
int main(){
	cin>>n;
	dfs(0);
	return 0;
}

下一种搜索方式:

就是比较原始的那种了,一个个格子放,可以就放,不行就算

#include<iostream>
using namespace std;
const int N = 20;
bool row[N], col[N], dg[N], udg[N];
int n;
char g[N][N];
void dfs(int x, int y, int cnt) {
	if (cnt > n) return ;
	if (y == n) x++, y = 0; //这里是搜的时候改变方向了
	if (x == n) {
		if (cnt == n) {
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < n; j++)
					cout << g[i][j];
				cout << "\n";
			}
            cout<<"\n";
		}
		return ;
	}
	g[x][y] = '.';
	dfs(x, y + 1, cnt); //一直横着搜,到顶点了就改变方向
	if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n]) {
		g[x][y] = 'Q';
		row[x] = col[y] = dg[x + y] = udg[x - y + n] = true;
		dfs(x, y + 1, cnt + 1);
		row[x] = col[y] = dg[x + y] = udg[x - y + n] = false;
		g[x][y] = '.';
	}
}
int main() {
	cin >> n;
	dfs(0, 0, 0);
	return 0;
}

路径寻找:

这里推荐一下经典例题:八数码:

​​​​​​845. 八数码 - AcWing题库

隐式图:图并不是事先给定,从程序读入,而是由程序动态生成叫做隐式图

路径寻找问题:

状态空间搜索一般是要找到一个从初始状态到终止状态的路径

刚刚八数码的题意是给你一个八数码的初始状态让你至少用多少步到达最终状态

太明显了,从初始状态到最终状态,并且没有给你任何的图,直接让你动态构造,典型的路径寻找问题,看看做做这个题吧,懂了之后收获会不小:

因为在某一个x,它都可以到上下左右四个方向,这就生成了四种不同的路径,每一种路径又可以生成,可以把每一种状态看成一个结点,就是bfs问题罢了,不过这个结点有点特殊是由八数码构成的,然后一层层扩展的时候,记录一下距离,这就和普通的bfs没啥区别了,最后肯定会扩展到一定的边界,如果扩展到答案了,就输出,实在没有就输出-1

#include<iostream>
#include<queue>
#include<unordered_map>
using namespace std;
int bfs(string start)
{
	queue<string> q;
	string end="12345678x";
	unordered_map<string,int> dist;
	q.push(start);
	dist[start]=0;
	while(q.size())
	{
		auto t=q.front();
		q.pop();
		int dis=dist[t];
		if(t==end) return dis;
		int k=t.find('x');//返回x的下标
		int x=k/3,y=k%3;
		int dx[4]={-1,1,0,0};
		int dy[4]={0,0,1,-1};
		for(int i=0;i<4;i++)
		{
			int xx=x+dx[i];
			int yy=y+dy[i];
			if(xx>=0&&xx<3&&yy>=0&&yy<3)
			{
				swap(t[k],t[3*xx+yy]);
				if(!dist.count(t))
				{
					dist[t]=dis+1;
					q.push(t);
				}
				swap(t[k],t[3*xx+yy]);
			}
		} 
	}
	return -1;
}
int main(){
	string start;
	for(int i=0;i<9;i++)
	{
		string c;
		cin>>c;
		start+=c;
	}
	cout<<bfs(start);
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值