The Morning after Halloween UVA - 1601

按照紫书的做法,创建两个对列,进行双向的BFS搜索,即可。具体实现见如下代码:

#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<deque>
using namespace std;

int w, h, n;
int dx[] = {0,1,-1,0,0};
int dy[] = {0,0,0,1,-1};
string *area;
int Start[3], End[3];
int Length[270];
int Edge[270][270];
int d1[270][270][270], d2[270][270][270];

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

bool feasible(int a,int a1,int b,int b1){
	if (a1 == b1 || (a==b1&&a1==b)) return false;
	return true;
}

int D_BFS(){
	queue<int> q1, q2;
	q1.push(ID(Start[0],Start[1],Start[2]));
	q2.push(ID(End[0], End[1], End[2]));
	
	memset(d1, -1, sizeof(d1));
	memset(d2, -1, sizeof(d2));

	d1[Start[0]][Start[1]][Start[2]] = 0;
	d2[End[0]][End[1]][End[2]] = 0;

	while (!q1.empty()&&!q2.empty()){
		queue<int> next_s;
		if (q1.size() < q2.size()){
			while (!q1.empty()){
				int front = q1.front(); q1.pop();
				int a, b, c;
				a = (front >> 16) & 0xff; b = (front >> 8) & 0xff; c = (front)& 0xff;
				for (int i = 0; i < Length[a]; i++){
					int a1 = Edge[a][i];
					for (int j = 0; j < Length[b]; j++){
						int b1 = Edge[b][j];
						if (!feasible(a, a1, b, b1)) continue;
						for (int k = 0; k < Length[c]; k++){
							int c1 = Edge[c][k];
							if (!feasible(a, a1, c, c1) || !feasible(b, b1, c, c1) || d1[a1][b1][c1] != -1) continue;
							d1[a1][b1][c1] = d1[a][b][c] + 1;
							if (d2[a1][b1][c1] != -1) return d1[a1][b1][c1] + d2[a1][b1][c1];
							if (a1 == End[0] && b1 == End[1] && c1 == End[2]) return d1[a1][b1][c1];
							next_s.push(ID(a1, b1, c1));
						}
					}
				}
			}
			q1 = next_s;
		}
		else{
			while (!q2.empty()){
				int front = q2.front(); q2.pop();
				int a, b, c;
				a = (front >> 16) & 0xff; b = (front >> 8) & 0xff; c = (front)& 0xff;
				for (int i = 0; i < Length[a]; i++){
					int a1 = Edge[a][i];
					for (int j = 0; j < Length[b]; j++){
						int b1 = Edge[b][j];
						if (!feasible(a, a1, b, b1)) continue;
						for (int k = 0; k < Length[c]; k++){
							int c1 = Edge[c][k];
							if (!feasible(a, a1, c, c1) || !feasible(b, b1, c, c1) || d2[a1][b1][c1] != -1) continue;
							d2[a1][b1][c1] = d2[a][b][c] + 1;
							if (d1[a1][b1][c1] != -1) return d1[a1][b1][c1] + d2[a1][b1][c1];
							if (a1 == Start[0] && b1 == Start[1] && c1 == Start[2]) return d2[a1][b1][c1];
							next_s.push(ID(a1, b1, c1));
						}
					}
				}
			}
			q2 = next_s;
		}
	}
	return -1;
}

int main(){
	while (cin >> w >> h >> n){
		if (w == 0 && h == 0 && n == 0) break;
		string del; getline(cin, del);
		area = new string[h];
		for (int i = 0; i < h; i++) getline(cin, area[i]);
		int index = 0;
		int id[270][270], x[270], y[270];
		memset(id,-1,sizeof(id));
		memset(x, -1, sizeof(x));
		memset(y, -1, sizeof(y));
		for (int i = 0; i < h; i++){
			for (int j = 0; j < w; j++){
				if (area[i][j] != '#'){
					x[index] = i; y[index] = j; id[i][j] = index;
					if (area[i][j] >= 'a'&&area[i][j] <= 'z') Start[area[i][j] - 'a']=index;
					if (area[i][j] >= 'A'&&area[i][j] <= 'Z') End[area[i][j] - 'A'] = index;
					index++;
				}
			}
		}
		memset(Length,0,sizeof(Length));
		for (int i = 0; i < index; i++){
			int tx = x[i], ty = y[i];
			for (int j = 0; j < 5; j++){
				int newx = tx + dx[j], newy = ty + dy[j];
				if (newx >= 0 && newx < h&&newy >= 0 && newy < w&&area[newx][newy] != '#'){
					Edge[i][Length[i]] = id[newx][newy];
					Length[i]++;
				}
			}
		}
		if (n <= 1){
			Start[1] = End[1] = index;
			Length[index] = 1;
			Edge[index][0] = index;
			index++;
		}
		if (n <= 2){
			Start[2] = End[2] = index;
			Length[index] = 1;
			Edge[index][0] = index;
			index++;
		}
		cout << D_BFS() << endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值