我的深度搜索和广度搜索的学习------题目记录

一,深度搜索

1.数字的全排列

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int a[10];//这个数组中一个一个放排的 
int flag[10];//这个数组标记数字是否放入 
int n;
void dfs(int step){
	if(step==n+1){
		for(int i=1;i<=n;i++)
		cout<<a[i];
		cout<<endl;
	}
	for(int i=1;i<=n;i++){
		if(flag[i]==0){
			a[step]=i;
			flag[i]=1;
			dfs(step+1);
			flag[i]=0;
		}
	}
}
int  main(){
	cin>>n;
	dfs(1);
} 

备注:一个数组进行标记,另一个数组进行放置的排列,一次排好以后输出排列结果;倒退回最近的一步进行选择再次进行排列。

2.二维数组寻找最少步数(走出迷宫最短步数)

(下标从1开始)

0 0 1 0

0 0 0 0

0 0 1 0

0 1 0 0

0 0 0 1

这样的一个5*4的矩阵,1代表路障,0可以走,从(1,1)出发,到(4,3)的位置

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int map[6][5];
int mins=999999;
bool flag[6][5]={false};
void dfs(int r,int c,int step){
	int tr=0,tc=0;
	int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
	if(r==4&&c==3){
		if(step<mins) mins=step;
		return;
	}
	for(int k=0;k<4;k++){
		tr=r+next[k][0];
		tc=c+next[k][1];
		if(tr>5||tr<1||tc>4||tc<1) continue;
		if(flag[tr][tc]==false&&map[tr][tc]==0){
			flag[tr][tc]=true;
			dfs(tr,tc,step+1);
			flag[tr][tc]=false;
		}
	}
	return;	
}
int main(){
	for(int i=1;i<6;i++){
		for(int j=1;j<5;j++){
			cin>>map[i][j];
		}
		cout<<endl;
	}
	flag[1][1]=true;
	dfs(1,1,0);
	cout<<mins;
} 

备注:与第一题不同在于 1,变成二维数组,需要开设两个二维数组,一个进行标记,另一个进行排列;2,有步数的加入,每一次递归都加一次步数,到达终点时将步数与之前步数进行比较,输出最小步数;3,分方向,循环的条件变为现在所在位置的四个方向的选择。 

3.求岛屿的面积

在一张二维地图中,数字代表海拔,0代表大海,求某一个点(比如6,8)所在岛屿的面积

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int sum;
int x,y;
int map[11][11]={
	0,0,0,0,0,0,0,0,0,0,0,
	0,1,2,1,0,0,0,0,0,2,3,
	0,3,0,2,0,1,2,1,0,1,2,
	0,4,0,1,0,1,2,3,2,0,1,
	0,3,2,0,0,0,1,2,4,0,0,
	0,0,0,0,0,0,0,1,5,3,0,
	0,0,1,2,1,0,1,5,4,3,0,
	0,0,1,2,3,1,3,6,2,1,0,
	0,0,0,3,4,8,9,7,5,0,0,
	0,0,0,0,3,7,8,6,0,1,2,
	0,0,0,0,0,0,0,0,0,1,0
};
bool flag[11][11]={false};
void dfs(int r,int c){
	int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
	int tr=0,tc=0;
	for(int i=0;i<4;i++){
		tr=r+next[i][0];
		tc=c+next[i][1];
		if(tr>10||tr<1||tc>10||tc<1) continue;
		if(map[tr][tc]>0&&flag[tr][tc]==false){
			sum++;
			flag[tr][tc]=true;
			dfs(tr,tc);
		}
	}
	return;
}
int main(){
	cin>>x>>y;
	flag[x][y]=true;
	if(map[x][y]<=0){
		sum=0;cout<<sum;
		return 0;
	}
	else sum=1;
	dfs(x,y);
	cout<<sum;
}  

备注:岛屿的面积,在dfs(tr,tc)之后,不需要将该点置于false,否则就变为路径的搜索。

 4.岛屿的数量

上题中有多少个岛屿

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int num=0;
int map[11][11]={
	0,0,0,0,0,0,0,0,0,0,0,
	0,1,2,1,0,0,0,0,0,2,3,
	0,3,0,2,0,1,2,1,0,1,2,
	0,4,0,1,0,1,2,3,2,0,1,
	0,3,2,0,0,0,1,2,4,0,0,
	0,0,0,0,0,0,0,1,5,3,0,
	0,0,1,2,1,0,1,5,4,3,0,
	0,0,1,2,3,1,3,6,2,1,0,
	0,0,0,3,4,8,9,7,5,0,0,
	0,0,0,0,3,7,8,6,0,1,2,
	0,0,0,0,0,0,0,0,0,1,0
};
bool flag[11][11]={false};
void dfs(int r,int c,int n){
	int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
	int tr=0,tc=0;
	map[r][c]=n;
	for(int i=0;i<4;i++){
		tr=r+next[i][0];
		tc=c+next[i][1];
		if(tr>10||tr<1||tc>10||tc<1) continue;
		if(map[tr][tc]>0&&flag[tr][tc]==false){
			flag[tr][tc]=true;
			dfs(tr,tc,n);
		}
	}
	return;
}
int main(){
	for(int i=0;i<11;i++){
		for(int j=0;j<11;j++){
			if(map[i][j]>0){
				num--;
				flag[i][j]=true;
				dfs(i,j,num);
			}
		}
	}
	cout<<-num;
}  

备注: 从左上角开始遍历寻找,找到一个岛将它置于num--(并深度搜索与该岛屿相连的所有岛都置于该num--),相当于划分板块,-1,-2,-3...板块,最后一个板块的负即为岛屿的个数了。

5.方格填数

如下的10个格子

填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)

一共有多少种可能的填数方案?

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int sum=0;
int num[3][4];
bool isfilled[10];
bool islegal(int r, int c, int val)
//第一排检查左右,第一列检查上和右上,第三列检查上,上左,左,其余检查左,上左,上,上右;
{
    if( r == 0 )
        return abs(val-num[r][c-1]) > 1;
    else if( c == 0 )
        return abs(val-num[r-1][c]) > 1 && abs(val-num[r-1][c+1])>1;
    else if( c != 3 )
        return abs(val-num[r][c-1]) > 1 && abs(val-num[r-1][c]) > 1 && abs(val-num[r-1][c-1])>1 && abs(val-num[r-1][c+1])>1;
    else
        return abs(val-num[r][c-1]) > 1 && abs(val-num[r-1][c]) > 1 && abs(val-num[r-1][c-1])>1;
}
void DFS(int  r,int c){
	if(r==2&&c==3){
		sum++;
		return ;
	}
	for(int i=0;i<10;i++){
		if(!isfilled[i]&&islegal(r,c,i)){
			num[r][c]=i;
			isfilled[i]=true;
			DFS(r+(c+1)/4,(c+1)%4);
//	if(c==3) DFS(r+1,0);
//  else DFS(r,c+1);
			isfilled[i]=false;
		}
	}
} 
int main(){
	num[0][0]=-10;
	num[2][3]=-10;
	for(int i=0;i<10;i++){
		isfilled[i]=false;
	}
	DFS(0,1);
	cout<<sum;
	return 0;
}

 6.寒假作业

每个方块代表1~13中的某一个数字,但不能重复。
比如:
 6  + 7 = 13
 9  - 8 = 1
 3  * 4 = 12
 10 / 2 = 5

以及: 
 7  + 6 = 13
 9  - 8 = 1
 3  * 4 = 12
 10 / 2 = 5

就算两种解法。(加法,乘法交换律后算不同的方案)

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int a[4][3];
int flag[14]={false};
int sum=0;
bool islegal(int r,int i){
	if(r==0){
		return a[r][0]+a[r][1]==i;
	}
	else if(r==1){
		return a[r][0]-a[r][1]==i;
	}
	else if(r==2){
		return a[r][0]*a[r][1]==i;
	}
	else if(r==3){
		return a[r][1]*i==a[r][0];
	}
	else return false;
}
void dfs(int r,int c){
	if(r==4){
		sum++;
		return;
	}
	for(int i=1;i<14;i++){
		if(!flag[i]){
			flag[i]=true;
			if(c!=2||islegal(r,i)){
				a[r][c]=i;
				dfs(r+(c+1)/3,(c+1)%3);
			}
					flag[i]=false;
			}
		}
	}
int main(){
	dfs(0,0);
	cout<<sum;
}

7.方格分割

6x6的方格,沿着格子的边线剪开成两部分。
要求这两部分的形状完全相同。
如图:p1.png, p2.png, p3.png 就是可行的分割法

试计算:
包括这3种分法在内,一共有多少种不同的分割方法。
注意:旋转对称的属于同一种分割法

式例

//以线进行分割,0-6;

#include <iostream>
#include <algorithm>
#include <set>
#include <queue>
#include <cstring>
#define MAX 100000
using namespace  std;
int map[7][7];
bool flag[7][7]={false};
int ans=0;
int next[4][2]={0,1,0,-1,1,0,-1,0};
void dfs(int r,int c){
	if(r==0||c==0||r==6||c==6){
		ans++;
		return;
	}
	for(int i=0;i<4;i++){
		int tr=r+next[i][0];
		int tc=c+next[i][1];
	//	if(tr<0||tc<0||tr>6||tc>6) continue;
		if(flag[tr][tc]==false){
			flag[tr][tc]=true;//
			flag[6-tr][6-tc]=true;
			dfs(tr,tc);
			flag[tr][tc]=false;
			flag[6-tr][6-tc]=false;
		}
	}
}
int main(){
	flag[3][3]=true;
	dfs(3,3);
	cout<<ans/4;
}

8.全球变暖

//蓝桥 ,用深搜写 太累了  ,先贴上,后补写广搜

#include <iostream>
#include <algorithm>
#include <set>
#include <queue>
#include <cstring>
#define MAX 100
using namespace std;
int n;
int map[MAX][MAX];
bool flag[MAX][MAX]={false};
void dfs(int r,int c,int val){
	int next[4][2]={0,1,0,-1,1,0,-1,0};
	int tr=0,tc=0;
	map[tr][tc]=val;
	for(int i=0;i<4;i++){
		 tr=r+next[i][0];
		 tc=c+next[i][1];
		if(tr<0||tc<0||tr>=n||tc>=n) continue;
		if(map[tr][tc]>1&&flag[tr][tc]==false) dfs(tr,tc,val);
	}
}
int main(){
	cin>>n;
	char ch;
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			cin>>ch;
			if(ch=='.') map[i][j]=0;
			else map[i][j]=1;
		}
	}
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			if(map[i][j]==1){
				if(map[i-1][j]==1&&map[i+1][j]==1&&map[i][j+1]==1&&map[i][j-1]==1)
				map[i][j]=2;
			}
		}
	}
	int ans=0;
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			if(map[i][j]>1){
				ans--;
				flag[i][j]=true;
				dfs(i,j,ans);
			}
		}
	}
	cout<<-ans;
//	for(int i=0;i<n;i++){
//		for(int j=0;j<n;j++){
//			cout<<map[i][j];
//		}
//		cout<<endl;
//	}
	
}

 

这两个博客写的很好,我看得第一个文章介绍,做的第二个题目。

算法入门

深度优先的八个简单小栗子

二、广度搜索

1.在一个n*m(n行, m列)的迷宫中,存在着一个入口、一些墙壁以及一个宝藏。由于迷宫是四连通的,即在迷宫中的一个位置,只能走到与它直接相邻的其他四个位置(上、下、左、右)。现洪尼玛在迷宫的入口处,问他最少需要走几步才能拿到宝藏?若永远无法拿到宝藏,则输出-1。

输入样例1:

3 3

S.#

.#.

.#E

输出 -1

输入样例2:

5 5

S.#..

#.#.#

#.#.#

#...E

#....

输出 7

#include <iostream>
#include <algorithm>
#include <set>
#include <queue>
#define MAX 101
using namespace  std;
char map[MAX][MAX];
bool vis[MAX][MAX]={false};//标记是否已经访问
struct point{//结构体存储该点的信息情况
	int r,c,num;
	point(int rr,int cc,int nn){
		r=rr;
		c=cc;
		num=nn;//搜索的范围(逐步扩大)
	}
};
int next[4][2]={1,0,-1,0,0,1,0,-1};
int flag,val,num=0;
int n,m;
queue<point> q;//用赌队列进行维护
void bfs(int sr,int sc){
	q.push(point(sr,sc,0));
	vis[sr][sc]=true;
	while(!q.empty()){
		point p=q.front();//p存储队列第一位的信息
		q.pop();
		if(map[p.r][p.c]=='E'){
			val=p.num;
			flag=1;
			break;
		}
		for(int i=0;i<4;i++){
		   	int tr=p.r+next[i][0];
			int tc=p.c+next[i][1];
			if(tr<0||tc<0||tr>=n||tc>=m) continue;//不可越界 
			if(map[tr][tc]!= '#'&&vis[tr][tc]==false){//判断条件
				q.push(point(tr,tc,p.num+1));
				vis[tr][tc]=true;
			}
		}
	}
}
int main(){
	flag=0;
	int r1,c1;
	cin>>n>>m;
	for(int i=0;i<n;i++){//赋值
		cin>>map[i];
	}
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(map[i][j]=='S'){//标记起点
				r1=i;
				c1=j;
			}
		}
	}	
	bfs(r1,c1);
	if(flag==0) cout<<"-1";
	else cout<<val;
	return 0;
} 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值