【算法学习笔记】12.数据结构基础 图的初步1

时间:2021-08-05 10:23:45


= ,=  妈蛋,拓扑排序和欧拉回路先放一放,实在有点力不从心。先继续学习暴力破解法。在那之前,把八连块和走迷宫先记录一下。

八连块,此名字十分坑爹,其实只要是连着的黑色区域都叫做一个八连块。计算一个图中黑色八连快的个数,

分析:利用DFS的思想来从0,0起点遍历整个图,遍历的过程中先是寻找到一个没有被访问过的黑色点,然后对这个点开始分散地递归地分析其周围的连块,直到遇到边界。此时也使得这个区域的黑色点比标记过。

下面是我的垃圾代码。


char s[1000]; 
int map[1000][1000][2];
//最后两个数值[0] 是存储的黑白0是白色 1是黑色;[1] 是是否被访问过0是没访问过 1是访问过 
//这是用了调用栈的方法来实现dfs的 ,但是这样做有可能造成溢出
void dfs(int x,int y)
{
	
	if(map[x][y][0]==0||map[x][y][1]==1)
		return;//如果是白色或者被访问过就返回
	map[x][y][1]=1;//自身被访问过 
	//否则开始递归访问周围的 
	dfs(x-1,y+1);	dfs(x,y+1);		dfs(x+1,y+1);
	dfs(x-1,y);						dfs(x+1,y);
	dfs(x-1,y-1);	dfs(x,y-1);		dfs(x+1,y-1);
}

int main()
{
	int n,cot=0;
	cin>>n;
	memset(map,0,sizeof(map));	//多维数组也可以这样清零
	for(int i=1;i<=n;i++)
	{
		cin>>s;
		for(int j=1;j<=n;j++)
			map[i][j][0]=s[j-1]-'0'; //此处用到了一种创造白色边界的方法来便于控制出界
	}
	
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(map[i][j][0]==1&&map[i][j][1]==0)
			{
				cot++;//每次读到一个黑色点即可认为读到了一个黑色八连块
				dfs(i,j);//开始在这个黑点周围释放毒气~
			}
		}
	}
	cout<<cot<<endl;
}

为了避免调用栈的溢出,不放选择用显式的栈来处理

stack<int> xs,ys;

void dfs(int x,int y)
{
	xs.push(x);ys.push(y);//首先将选中的黑色点压入栈底
	while(!xs.empty())
	{
		int xt=xs.top();
		int yt=ys.top();
		if(map[xt][yt][0]==0||map[xt][yt][1]==1)
		{	xs.pop();ys.pop();	continue;}
		map[xt][yt][1]=1;//标志被访问过
<span style="white-space:pre">		</span>//开始讲周围的8点压入栈 准备进行处理,每次处理时又会进行压入,所以这种方法其实还是效率蛮低的
<span style="white-space:pre">		</span>//改良的话不放考虑一下xt,yt的范围
		xs.push(xt-1);ys.push(yt-1);
		xs.push(xt-1);ys.push(yt);
		xs.push(xt-1);ys.push(yt+1);
		xs.push(xt);ys.push(yt-1);
		xs.push(xt);ys.push(yt+1);
		xs.push(xt+1);ys.push(yt-1);
		xs.push(xt+1);ys.push(yt);
		xs.push(xt+1);ys.push(yt+1);
	}
}

这种时候发现递归其实并不一定适用于各种情况

下面研究一个最短路问题(貌似是叫这个名字)

走迷宫,寻找最短路线(其中一种就行,其实也只能找出来一种


分析时,考虑怎么样才能得到最短路线。

1.把地图上每个点距离起点的最短距离写出来

2.把每个点的上一个来源找到(指的是实现起点到此点最短距离的路线)

下面是代码

其实我对BFS和DFS的理解还是不透彻,只是知道BFS用队列,DFS用栈(递归)

#include <stdio.h>
#include <iostream>
#include <queue>
#define M 1000
using namespace std;

int maze[M][M];//存储地图 1是空地 0是陷阱 
char s[M];//存储临时输入变量
char name[]={' ','U','D','L','R'};//1 2 3 4 分别对应的走向 
int n,m;//地图宽度n 地图高度m 
int dist[M][M],father[M][M];//dist 用来记录距离 father用来记录父节点 
bool isvit[M][M]={false};//记录是否被走过,默认是false 没走过 
int last_dir[M][M];
//下面两个数组非常简洁的解决了如何处理防线转换的判断问题
int dx[5]={0,0,0,-1,1};
int dy[5]={0,-1,1,0,0};
char path[M*M];

//bfs 用来遍历整个地图 同时进行标记每个点到起点的距离 
//参数是起点的位置 0,0 
void bfs(int x,int y) 
{	
	queue<int> q; //用来存储即将要处理的节点,由于是bfs则用队列处理 	
	int u =x+n*y;//记下起点编号 
	isvit[x][y]=true;//走过了
	father[x][y]=u;//起点的父节点就是起点本身
	dist[x][y]=0;//自己到自己是0 
	//开始遍历队列中的节点 
	q.push(u);//第一个要处理的就是起点
	while(!q.empty()) 
	{
		u=q.front();//记下即将要处理的节点编号
		q.pop();//表示已经开始接受处理
		int ux=u%n,uy=u/n;
		for(int i=1;i<=4;i++)
		{ 
			int tx=ux+dx[i];
			int ty=uy+dy[i];
			//tx ty 不越界且是空地 且没有被访问过 
			if(tx>=0&&tx<n&&ty>=0&&ty<m&&maze[tx][ty]&&!isvit[tx][ty])
			{
				dist[tx][ty]=dist[ux][uy]+1;//起点到此扩展节点的距离就是起点到其父节点最短距离+1
				father[tx][ty]=u;//记录父节点
				isvit[tx][ty]=true;//标志被访问过
				last_dir[tx][ty]=i; 
				int v=tx+ty*n;
				q.push(v);
			}
		}
	}
}

//打印路线图 递归调用 向上一个节点靠近 反向输出 
void print_path(int x,int y)
{
	int fa=father[x][y];
	if(x==0&&y==0) return; //因为路线过程中只有起点的父节点是0,0需要直接退回
	
	int tx=fa%n;
	int ty=fa/n;		
	print_path(tx,ty);//起点的父节点是0,0 所以会退回 其他的点都有父节点
	cout<<name[last_dir[x][y]];
	
}
//不用递归来做防止栈越界

void print_path2(int x,int y) 
{
	int i=0;
	while(!(x==0&&y==0))
	{
		int fa=father[x][y];
		int tx=fa%n;
		int ty=fa/n;		 
		path[i++]=name[last_dir[x][y]];
		x=tx;y=ty;//此处相当于更新了队首元素
	} 
	//此时i比下标上限大1 
	while(i>0)
	{
		cout<<path[--i]; 
	}
}
int main()
{
	freopen("in47.txt","r",stdin);
	freopen("out47.txt","w",stdout);
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		
		cin>>s;
		for(int j=0;j<n;j++)
			maze[j][i]=s[j]-'0';
	}
	bfs(0,0);
	for(int i=0;i<m;i++)
	{ 
		for(int j=0;j<n;j++)
			cout<<dist[j][i]<<"\t";
		cout<<endl;
	}
	cout<<endl;	cout<<endl;	cout<<endl;
	for(int i=0;i<m;i++)
	{ 
		for(int j=0;j<n;j++)
			cout<<father[j][i]<<"\t";
		cout<<endl;
	}
	cout<<endl;	cout<<endl;	cout<<endl;
	print_path(4,0);
	cout<<endl;	
	print_path2(4,0);
	return 0;
}