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]);
}
}