双向bfs, A*以及其他搜索算法

总结

例题

1

万圣节后的早晨

普通bfs

重点在代码里

//以下关于编码解码的内容,以后再看,现在注重算法 
#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
using namespace std;
const int N = 20;
const int MAXN = 200;// 75% cells plus 2 fake nodes
const int mx[] = {-1, 1, 0, 0, 0};
const int my[] = {0, 0, -1, 1, 0};//包括不移动 

inline int ID(int a, int b, int c) {//编码 
	return (a<<16)|(b<<8)|c;
}

int r, c, n;
int s[3], t[3];//三只鬼的起点&终点

int G[MAXN][6];
//重点1 : G用来把空格重组成一张图,G[i][0]表示标号为i的空格周围能走的格子数//邻接表嘛 
//G[i][1~5]表示下一步鬼从i可以走到的空格的编号 (其实也可以记录dir 

inline int comflict(int a, int b, int a2, int b2) {
//	return (a==a2&&b==b2) || (a==b2&&b==a2); 这是我傻了...这不是坐标!这是编号 
	return a2 == b2 || (a2 == b && b2 == a);//判断同时移动的时候是否冲突 
}

int dis[MAXN][MAXN][MAXN];

int bfs() {
	queue<int> q;
	memset(dis, -1, sizeof(dis));
	q.push(ID(s[0], s[1], s[2]));
	dis[s[0]][s[1]][s[2]] = 0;
	while(!q.empty()) {
		int u = q.front(); q.pop();
		int a = (u>>16)&0xff, b = (u>>8)&0xff, c = u&0xff;//解码 
		if(a==t[0] && b==t[1] && c==t[2]) return dis[a][b][c];
		
		for(int i = 1; i <= G[a][0]; i++) {
			int a2 = G[a][i];
			for(int j = 1; j <= G[b][0]; j++) {
				int b2 = G[b][j];
				if(comflict(a, b, a2, b2)) continue;
				for(int k = 1; k <= G[c][0]; k++) {
					int c2 = G[c][k];
					if(comflict(a, c, a2, c2)) continue;
					if(comflict(b, c, b2, c2)) continue;
					if(dis[a2][b2][c2] != -1) continue;
          			dis[a2][b2][c2] = dis[a][b][c]+1;
            		q.push(ID(a2, b2, c2));
				}
			}
		}
	}
	return -1;
}

int main() {
	while(scanf("%d%d%d
", &c, &r, &n) == 3 && n) {//记得在这加上“
” 
		char M[N][N];//以后这样的,不是全局变量的,只在main里面声明就行了,不用init了
		for(int i = 0; i < r; i++) {
			fgets(M[i], 20, stdin); 
//			printf("	%d
", i);
		}
		//从原图中抽出空格,并确定初末位置
		int cnt, x[MAXN], y[MAXN], id[MAXN][MAXN];//用id[][]来给G[][]赋值,这样会方便很多 
		cnt = 0; //cnt:空格数(顺便编号
		for(int i = 0; i < r; i++) 
			for(int j = 0; j < c; j++) if(M[i][j] != '#') {
				x[cnt] = i; y[cnt] = j; id[i][j] = cnt;
				if(islower(M[i][j])) s[M[i][j] - 'a'] = cnt;
				else if(isupper(M[i][j])) t[M[i][j] - 'A'] = cnt;
				cnt++;
			} 
		
		//用空格,邻接表建图: 即计算G 
		for(int i = 0; i < cnt; i++) {
			G[i][0] = 0;
			for(int dir = 0; dir < 5; dir++) {
				int x2 = x[i]+mx[dir], y2 = y[i]+my[dir];
				if(M[x2][y2] != '#') G[i][++G[i][0]] = id[x2][y2];//由题意:没必要判越界 
			}
		} 
		
		//重点2: 添加fake节点,简化code
		if(n <= 2) {G[cnt][0] = 1; G[cnt][1] = cnt; s[2] = t[2] = cnt; cnt++;}
		if(n <= 1) {G[cnt][0] = 1; G[cnt][1] = cnt; s[1] = t[1] = cnt; cnt++;}
		
		printf("%d
", bfs()); 
	}
	return 0;
}
原文地址:https://www.cnblogs.com/tyner/p/12080218.html