[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了很久才發現某個條件寫錯了。
在這裏插入圖片描述

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