IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 回溯法--棋盘类 -> 正文阅读

[数据结构与算法]回溯法--棋盘类

这类问题需要注意三个问题
1、存储问题:一般用二维数组存储
2、枚举对象:一般以坐标作为枚举对象
3、坐标增量:二维数组或者两个一维数组

迷宫问题

先看一个简易迷宫问题吧

现在有一个小迷宫,如图所示,请编程求解从入口到终点的最短路径。
迷宫由n行m列的单元格组成,且n,m小于等于50.注意黑色区域快不可以走,只能走白色区域。

在这里插入图片描述

输入: 第一行:n,m,分别代表n行m列。
第2-n行表示为迷宫,0表示空地,1表示障碍物。
最后一行,x,y,p,q前两个为入口坐标,后两个为终点坐标。 输出: 最短路径

样例输入:
5 4
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1
1 1 4 3
样例输出;
7

【分析问题】
一、分析题意:
从入口可以向右和向下走,一次遍历所有的路径,找出可以走的路径,记录可以到达终点的路径,并打擂台的形式找出最短路径。

二、算法分析
1、规定一个走的顺序,按照顺时针的方向来尝试,即按照右、下、左、上的顺序去尝试所有路径。
2、用深搜来实现这个方法。那么dfs()函数如何写呢?
dfs()的功能是解决当前应该怎么办;
1)检查是否已经到终点(比较容易实现吧)
dfs()只需要维护三个参数,分别为当前这个点的坐标x,y以及当前已经走过的步数step

void dfs(int x,int y,step)
{
   if(x==p&&y==q)//判断是否到达终点
	{
    if(step<min)//打擂台更新最小值
      min=step;
   return;//注意这里的返回很重要哦。
	}
}

2)如果没有到达终点,找出下一步可以走的地方。
用一个方向数组next[4][2]来定义四个方向。

int next[4][2]={{01},{1,0},{0,-1},{-1,0}};

在这里插入图片描述

通过这个方向数组,使用循环就很容易获得下一步的坐标,这里用tx,ty存储坐标。

for(int k=0;k<=3;k++)
 {
	tx=x+next[k][0];
	ty=y+next[k][1];
  }

为了避免重复访问一个点,需要用book[tx][ty]来记录(tx,ty)是否已经在路径中。

如果这个点符合所有的要求,就对这个点进行下一步的扩展,即dfs(tx,ty,step+1)。

代码如下:

for(int k=0;k<=3;k++)
 {
tx=x+next[k][0];
ty=y+next[k][1];
//判断是否越界
if(tx<1||tx>n||ty<1||ty>m)
  continue;
//判断该点是否可走或者是否在路径中
if(a[tx][ty]==0&&book[tx][ty]==0)
 {
  book[tx][ty]=1;
   dfs(tx,ty,step+1);
   book[tx][ty]=0;//回溯

    }

来看一下完整代码吧

#include<iostream>
using namespace std;
int n,m,p,q,minn=9999;
int a[51][51],book[51][51];
void dfs(int x,int y,int step)
{
	int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
//通过这个方向数组,使用循环就很容易获得下一步的坐标,这里用tx,ty存储坐标。
 int tx,ty,k;
 if(x==p&&y==q)//判断是否到达终点
{
    if(step<minn)//打擂台更新最小值
      minn=step;
   return;//注意这里的返回很重要哦。
}
//枚举4种走法 
for(int k=0;k<=3;k++)
 {
 	//计算下一个点的坐标 
tx=x+next[k][0];
ty=y+next[k][1];
//判断是否越界
if(tx<1||tx>n||ty<1||ty>m)
  continue;
//判断该点是否可走或者是否在路径中
if(a[tx][ty]==0&&book[tx][ty]==0)
 {
   book[tx][ty]=1;
   dfs(tx,ty,step+1);
   book[tx][ty]=0;//回溯

  }
  }
  return;
 } 
 int main()
 {
 	int i,j,sx,sy;
 	cin>>n>>m;
 	//读入迷宫 
 	for(i=1;i<=n;i++)
 	  for(j=1;j<=m;j++)
 	    cin>>a[i][j];
 	//读入起点和终点坐标
	 cin>>sx>>sy>>p>>q;
	 //从起点开始搜索,将起点纳入路径中 
	 book[sx][sy]=1;
	 dfs(sx,sy,0);
	 cout<<minn;
	 return 0;
  } 

八皇后问题

【问题解析】
1、枚举对象当然是8个皇后了,但是要求同行、同列、同对角线不能冲突,因此,我们枚举每一行的皇后放置,这样只需要判断同列、同对角线即可。
在这里插入图片描述

2、同对角线的判定
在这里插入图片描述
黑色表示主对角线(x-y+n),红色表示副对角线(x+y)
在这里插入图片描述
在这里插入图片描述
【参考代码】

#include<bits/stdc++.h>
using namespace std;
#define maxn 100
int a[maxn],b1[maxn],b2[maxn],b3[maxn];//分别记录x,x+y,x-y+15是否被占用
int n ,ans = 0;
void dfs(int x)
{
	if(x>n)
	{
		ans++;
		if(ans<=3)
		{
			for(int i = 1;i <= n;i++)
			{
				cout<<a[i]<<" ";
			}
			cout<<endl;
		}
		return ;
	}
	for(int i = 1;i<=n;i++)
	{
		if(b1[i]==0 && b2[x+i]==0 && b3[x-i+15]==0)
		{
			a[x]=i;
			b1[i]=1;
			b2[x+i]=1;
			b3[x-i+15]=1;
			dfs(x+1);
			b1[i]=0;
			b2[x+i]=0;
			b3[x-i+15]=0;
		}
	}
 } 
 int main()
 {
 	cin>>n;
 	dfs(1);
 	cout<<ans;
 }

数独问题

简化问题,我们先来看四阶数独。
1、枚举对象:我们来填空,每个空都填完,枚举结束
在这里插入图片描述

2、判定同行,同列,同方格是否重复
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
#define size 5
int a[size*size],n= 4*4,ans = 0;
int b1[size][5],b2[size][5],b3[size][5];//分别记录 横行、竖行、四小块
void dfs(int x)//第x个空填什么
{
	if(x>n)
	{
		ans++;//统计方案数 
		for(int i = 1;i<=n;i++)//输出方案 
		{
			cout<<a[i]<<" ";
			if(i%4==0) cout<<endl; 
		}
		cout<<endl;
		return ;
	}
	int row = (x-1)/4+1;
	int col = (x-1)%4+1;
	int block = (row-1)/2*2+(col-1)/2+1;
	for(int i = 1;i<=4;i++)
	{
		if(b1[row][i]==0&&b2[col][i]==0&&b3[block][i]==0)
		{
			a[x]=i;
			b1[row][i]=1;
			b2[col][i]=1;
			b3[block][i]=1;
			dfs(x+1);
			b1[row][i]=0;
			b2[col][i]=0;
			b3[block][i]=0;
			
		}
	}
 } 
 int main()
 {
 	dfs(1);
 	cout<<ans;
 	return 0;
 }

临时抱佛脚

【题解】从这些题目中取其中一部分作为一个子集,使这些题目总耗时不超过这个科目的总耗时的一半,但是尽可能大。这样就可以将这个科目的题目分为尽可能均等的两部分了。
可以借鉴之前讲过的枚举子集—每个题目放入或者不放入子集中。

#include<bits/stdc++.h>
using namespace std;
int nowt,maxt,sum;
int ans,maxdeep;//最深递归层数(作业数量) 
int s[4],a[21];
void dfs(int x)
{
	if(x > maxdeep)//所有作业枚举完毕,达到了最大递归层数 
	{
		maxt = max(maxt,nowt);
		return ;
	}
	if(nowt +a[x]<=sum/2)
	{
		nowt += a[x];
		dfs(x+1);//下一层递归 
		nowt-=a[x];
	}
	dfs(x+1);//不选这科 
}
int main()
{
	cin>>s[0]>>s[1]>>s[2]>>s[3];
	for(int i = 0;i<4;i++)
	{
		nowt = 0;
		maxdeep = s[i];
		sum = 0;//别忘了每次换科都要初始化 
		for(int j = 1;j<=s[i];j++)
		{
			cin>>a[j];
			sum+=a[j];//记录这科总耗时 
		}
		maxt = 0;
		dfs(1);
		ans += (sum-maxt);//加上答案 
	}
	cout<<ans;
}

更多练习

1、炮兵阵地
2、数独easy

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-05-11 16:39:00  更:2022-05-11 16:39:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 3:36:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码