[kuanbin带我飞]简单搜索

今天做了几道kuanbin专题,今天做的算是搜索入门题吧,不过自己确实做得够呛(黑脸)

迷宫问题 POJ - 3984

在这里插入图片描述
这道题就是bfs的模板题了,题意很简单,就找到从左上角到右下角的最短路线,这又让我想到前天CometOJ的最后一题I,那时候做的时候以为是同类型的,所以想的有些复杂,最后自己才发现有套路,那道题是障碍随机,即只要找到最短路就好了。

这里用到了结构体,用来存放输入的座标还有值,其中值1代表障碍,0代表可以走,用了 l 数组记录下一步方向,以路径的长度作为下标,因为一条路径对应每一段长度的是唯一的。其中走路的方向我用两个数组来存储,这样就可以利用循环来尝试。用a数组记录是否走过。用judge函数判断是否可以走。用bfs函数解题,这里用到了队列,这个算是一个模板,先将第一个数据初始化入栈,然后再不断地更新队列,入栈出栈,入栈后用 l 数组记录方向。

PS:悄咪咪地说一句,这道题的测试数据只有示例那一组,有些人就直接输入输出就Accepted,而且内存超小速度快。

//bfs
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
//# define LOCAL
using namespace std;
const int maxn = 5;
int map[maxn][maxn];//图 
bool a[maxn][maxn];//记录是否走过 
int dx[4]={0,-1,0,1}; 
int dy[4]={-1,0,1,0};//走路方向 
struct node{
	int x,y,s;
	short l[30];
};
bool judge(int i,int j){
	if(i<0 || i>=maxn || j<0 || j>=maxn)		return true;//边界 
	if(a[i][j]==true)	return true;//走过 
	if(map[i][j] == 1)	return true;//障碍 
	return false;
}
node bfs(){
	queue<node> q;
	node cur,next;
	cur.x = 0,cur.y = 0,cur.s = 0;
	a[cur.x][cur.y] = true;
	q.push(cur);
	while(!q.empty()){
		cur = q.front();
		q.pop();
		if(cur.x == maxn-1 && cur.y == maxn-1)
			return cur;
		for(int i=0;i<maxn-1;i++){
			int nx = cur.x + dx[i];
			int ny = cur.y + dy[i];//尝试向这个方向走
			if(judge(nx,ny))
				continue;
			next = cur;//往下走 
			next.x = nx;
			next.y = ny;
			next.s = cur.s + 1;
			next.l[cur.s] = i;
			q.push(next);
			a[next.x][next.y] = true;
		}
	}
	return cur;
}
inline int read(){
	char ch=getchar();int f=1,x=0;
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int main(){
#ifdef LOCAL
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
#endif
	for(int i=0;i<maxn;i++)
		for(int j=0;j<maxn;j++)
			map[i][j] = read();
	//		scanf("%d",&map[i][j]);
	memset(a,0,sizeof(a));
	node ans = bfs();
	int x=0,y=0;
	for(int i=0;i<=ans.s;i++){
		printf("(%d, %d)\n",x,y);
		x += dx[ans.l[i]];
		y += dy[ans.l[i]];
	}
	return 0;
}

Ordering Tasks UVA - 10305

这道是紫书上的一道,任务安排,这里我用了两种方法,紫书使用数组,这里还写了一种利用队列。
在这里插入图片描述
这道题也算是拓扑排序的一道模板题,其中讲到拓扑排序,需要了解下概念

  • 拓扑排序

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。 通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。

其中我们需要知道的是,如果图中存在有向环,则不存在拓扑排序,反之则存在。不包含有向环的有向图成为有向无环图(DAG)。

紫书用到的技巧是,利用c数组,c[u]=0表示从来没有访问过(从来没有调用过dfs(u));c[u]=1表示已经访问过,并且还递归访问它所有子孙(即dfs()曾被调用过,并已返回);c[u]=-1表示正在访问(即递归调用dfs(u)正在栈帧中,尚未返回)。

这里讲一下队列实现的方法:
其中deg数组存储的是结点的入度,其中入度是指以该结点为终点的有向边的条数。
拓扑排序的过程思想很简单,我们只需要不断地选择图中入度为0的结点,然后把x连向的点的入度减1。
代码中,用G数组存储是否已排序,topo存储排序好的序列。这里需要注意的是题目要求是输出的是从1开始的,所以我们最好在存入数据的时候就从1开始,省去麻烦。

#include<cstdio>
#include<cstring>
#include<queue>
# define LOCAL
using namespace std;
const int maxn = 105;
int G[maxn][maxn];
int c[maxn],topo[maxn];
int m,n,t;
bool dfs(int u){
	c[u] = -1;//标志正在访问 
	for(int v=1;v<=n;v++){
		if(G[u][v]){
			if(c[v] < 0)
				return false;
			else if(!c[v] && !dfs(v))
				return false;			
		}
	} 
	c[u] = 1;//标记已经访问过了 
	topo[--t] = u;
	return true;
}
bool toposort(){
	t = n;
	memset(c,0,sizeof(c));
	for(int u=1;u<=n;u++)
		if(!c[u])
			if(!dfs(u))
				return false;
	return true;
}

int deg[maxn];
void  Sort(){//拓扑排序 
	queue<int> q;
	int cnt = 0;
	for(int i=1;i<=n;i++)
		if(deg[i]==0)
			q.push(i);
	while(!q.empty()){
		int u = q.front();
		q.pop();
		topo[cnt++] = u;
		for(int v=1;v<=n;v++){
			if(G[u][v])
				if(--deg[v] == 0)
					q.push(v);
		}
	}
	for(int i=0;i<cnt;i++)
		printf("%d ",topo[i]);
	printf("\n");
}


int main(){
#ifdef LOCAL
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
#endif
	while(scanf("%d%d",&n,&m)==2 && (m||n)){
		memset(G,0,sizeof(G));
		memset(deg,0,sizeof(deg));
		for(int i=0;i<m;i++){
			int u,v;
			scanf("%d%d",&u,&v);
			G[u][v] = 1;
			deg[v] ++;			
		}
/*		if(toposort()){
			for(int i=0;i<n;i++)
				printf("%d ",topo[i]);
			printf("\n");
		}*/
		Sort();
	}
	return 0;
}

Dungeon Master POJ - 2251

在这里插入图片描述

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<vector>
# define LOCAL
using namespace std;
const int maxn = 35;
char mp[maxn][maxn][maxn];//map
bool vis[maxn][maxn][maxn];//judge
int sl,sx,sy,el,ex,ey; //start and end 
int dic[6][3]={{-1,0,0},{1,0,0},{0,-1,0},{0,1,0},{0,0,-1},{0,0,1}};	//direction
int l,r,c;
priority_queue<node> q;	//定义优先队列
struct node{
	int l,x,y;
	int step;e
	friend bool operator < (node a,node b){
		return a.step > b.step;	//优先队列,小的先访问 
	}
};
bool judge(int i,int j,int k){	//判断 
	if(i<0 || j<0 || k<0 || i>=l || j>=r || k>=c)	return false;
	if(mp[i][j][k]=='#')	return false;
	if(vis[i][j][k])	return false;
	return true;
}

void bfs(){
	node p;
	p.l = sl, p.x = sx, p.y = sy;//起点 
	p.step = 0;
	vis[p.l][p.x][p.y] = true;
	q.push(p);	//入栈 
	while(!q.empty()){
		node cur = q.top();
		q.pop();
		if(cur.l==el && cur.x==ex && cur.y==ey){
			printf("Escaped in %d minute(s).\n",cur.step);
			return;
		}//到达终点 
		for(int i=0;i<6;i++){
			int nl = cur.l + dic[i][0];
			int nx = cur.x + dic[i][1];
			int ny = cur.y + dic[i][2]; //尝试各个方向 
			if(judge(nl,nx,ny)){
					node next;
					next.l = nl,next.x = nx,next.y = ny;
					next.step = cur.step + 1;
					vis[next.l][next.x][next.y] = true;
					q.push(next);
			}
		}
	}
	printf("Trapped!\n");
}

int main(){
#ifdef LOCAL
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
#endif
	while(scanf("%d%d%d",&l,&r,&c)==3 && ( l || r || c )){
		for(int i=0;i<l;i++){
			for(int j=0;j<r;j++){
			//	cin >> mp[i][j];
				scanf("%s",mp[i][j]);
			//	cout << mp[i][j] << "\n";
				for(int k=0;k<c;k++){
					if(mp[i][j][k] == 'S'){
						sl = i,	sx = j,	sy = k;//找到起点 
					}else if(mp[i][j][k] == 'E'){
						el = i,	ex = j,	ey = k;
					}//找到终点 
				}
			}
		//	getchar();			
		}
		memset(vis,0,sizeof(vis));
		bfs();
	}
	return 0;
}

这道题其实和第一道迷宫问题很像,只是方向从2维变成3维,我们只需要在方向上做改动,然后再多维护一个变量就可以了。这里用到了优先队列,因为路径可能有很多条,我们需要维护路径最短的。这里把判断条件还是放在函数里,需要用的时候调用,这样也使得代码比较清晰,便于找到BUG,不然可能会有下面这样的情况,debug了很久才发现某个条件写错了。
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章