【ybtoj】【BFS】【例题5】电路维修

【例题5】电路维修


Link

传送门
题目


解题思路

每一根电线有四种情况(●是电连到哪)
在这里插入图片描述
每一种情况的下一根电线连接坐标变化,和下一根电线的状态提前预处理出来
举个栗子
在这里插入图片描述
对于每一根电线,尝试往它可连接三条电线扩展
如果和预期电线不一样,就翻转电线
在这里插入图片描述
在这里插入图片描述
对于预期电线和实际电线的比较
我把方向相同的电线的编号统为偶数和奇数了(没想到吧)
在这里插入图片描述

关于BUG
程序是有一点小问题,所以导致有几个“NO SOLUTION”的情况也出现答案
HKY巨爷找到规律
( n + m ) % 2 = 0 (n+m)\%2=0 (n+m)%2=0有解
( n + m ) % 2 = 1 (n+m)\%2=1 (n+m)%2=1无解
然后我懒得改程序,直接用规律过数据了


Code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>

using namespace std;

const int way[4][3][3] = { { { -1, -1, 0 }, { -1, 0, -1 }, { 0, 1, 3 } }, 
						   { { -1, -1, 0 }, { 0, 1, 1 }, { 0, 1, 2 } }, 
						   { { 0, 1, 1 }, { 1, 0, 1 }, { 1, 3, 2 } }, 
						   { { 0, 1, 1 }, { -1, -1, 0 }, { 0, 3, 2 } } };
struct DT{
	int x, y, k;
}now;
int T, n, m, a[510][510], v[510][510];
queue<DT> q;
char c;

bool check(int x, int y) { return (x > 0 && x <= n && y > 0 && y <= m); }

void BFS() {
	q.push((DT){1, 1, 2});
	memset(v, 0x7f, sizeof(v));
	v[1][1] = a[1][1];
	while (!q.empty()) {
		now = q.front();
		if (v[now.x][now.y] >= v[n][m]) {//如果当前翻转次数已经超过了当前答案,不需要往下做了
			q.pop();
			continue;
		}
		for (int i = 0; i < 3; i++) {
			int xx = now.x + way[now.k][0][i], yy = now.y + way[now.k][1][i], kk = way[now.k][2][i];
			if (!check(xx, yy)) continue;
			if ((kk % 2) == (a[xx][yy] % 2)) {//相同
				if (v[now.x][now.y] < v[xx][yy]) {//类似SPFA的路径松弛
					v[xx][yy] = v[now.x][now.y];
					if ((xx != n || yy != m) && (xx != 1 || yy != 1))
						q.push((DT){xx, yy, kk});
				}
			} else {//不相同,需要翻转
				if ((v[now.x][now.y] + 1) < v[xx][yy]) {
					v[xx][yy] = v[now.x][now.y] + 1;
					if ((xx != n || yy != m) && (xx != 1 || yy != 1))
						q.push((DT){xx, yy, kk});
				}
			}
		}
		q.pop();
	} 
}

int main() {
	scanf("%d", &T);
	while (T--) {
		scanf("%d%d", &n, &m);
		memset(a, 0, sizeof(a));
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++) {
				cin >> c;
				if (c == '/')
					a[i][j] = 1;
			}
		BFS();
		if ((n + m) % 2)//规律过数据
			printf("NO SOLUTION\n");
		else
			printf("%d\n", v[n][m]);
	}
} 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值