搜索_BFS_双端队列BFS_CH2601_电路维修

版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/84306813

点此打开题目页面

    思路分析: 考虑使用BFS, 计算左上角结点至通过对角线(可旋转)到达的各个结点的最短距离, 如果两个对角结点A, B之间无连线, 那么欲使A, B相连, 需要旋转A, B对应区域的对角线. 此时设A, B之间距离为1, 如果A, B之间有连线那么距离为0, 为了实现更佳有效的剪枝, 考虑每次从对头取出元素进行扩展时, 将需要加入队列的到起点距离较大的结点放在队尾, 到起点距离较小的结点放在队头, 具体实现如下AC代码所示:

//CH2601_电路维修
#include <iostream>
#include <deque>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define mp make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 505;
char G[MAX][MAX]; int R, C, d[MAX][MAX];
int main(){
	int T; scanf("%d", &T);
	while(T--){
		scanf("%d %d", &R, &C);
		for(int i = 1; i <= R; ++i) scanf("%s", G[i] + 1);
		memset(d, 0x3f, sizeof(d));
		deque<pair<int, int> > dq; dq.push_back(mp(0, 0)), d[0][0] = 0;
		while(!dq.empty()){
			int x = dq.front().fi, y = dq.front().se; dq.pop_front();
			//考察左上结点
			if(x - 1 >= 0 && y - 1 >= 0){
				int len = G[x][y] == '\\'? 0: 1, t = d[x][y] + len, &k = d[x - 1][y - 1];
				if(t < k) {
					k = t; if(len) dq.push_back(mp(x - 1, y - 1)); else dq.push_front(mp(x - 1, y - 1));	
				}
			} 
			//考察右上结点
			if(x - 1 >= 0 && y + 1 <= C){
				int len = G[x][y + 1] == '/'? 0: 1, t = d[x][y] + len, &k = d[x - 1][y + 1];
				if(t < k){
					k = t; if(len) dq.push_back(mp(x - 1, y + 1)); else dq.push_front(mp(x - 1, y + 1));
				}
			} 
			//考察左下结点
			if(x + 1 <= R && y - 1 >= 0){
				int len = G[x + 1][y] == '/'? 0: 1, t = d[x][y] + len, &k = d[x + 1][y - 1];
				if(t < k){
					k = t; if(len) dq.push_back(mp(x + 1, y - 1)); else dq.push_front(mp(x + 1, y - 1));
				}
			} 
			//考察右下结点
			if(x + 1 <= R && y + 1 <= C){
				int len = G[x + 1][y + 1] == '\\'? 0: 1, t = d[x][y] + len, &k = d[x + 1][y + 1];
				if(t < k) {
					k = t; if(len) dq.push_back(mp(x + 1, y + 1)); else dq.push_front(mp(x + 1, y + 1));
				}
			} 
		}
		if(d[R][C] == 0x3f3f3f3f) printf("NO SOLUTION\n"); else printf("%d\n", d[R][C]);
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/solider98/article/details/84306813