链接 175.电路维修
题意
给出一个 n * m 的网格图,从左上角走到右下角,每个方块中有一个可旋转的、连接一条对角线上的两个接点的线,只能走斜线,而不能走直线,输出最小的旋转次数;
思路
左上角的点为(0,0),右下角的点为(n,m),可以得知图中的粉色的点是不可以到达的
所以可以推断出,坐标和为奇数的点是不能到达的,可以得出无解的条件即为n + m为奇数时
要用到双端队列来进行存点,0 的权值点插到队列头,1 的权值点插到队列尾(这里权值为,不翻转为 0,翻转一次为 1);
因为存进去的图时为一个一个的方格,而 bfs 是以点进行 bfs 的,所以要用到数组偏移量
int dx[] = {-1, -1, 1, 1}, dy[] = {-1, 1, 1, -1};
int ix[] = {-1, -1, 0, 0}, iy[] = {-1, 0, 0, -1};
其中dx,dy为点的扩展点,ix,iy则为到扩展点用了哪条边(也就是哪个方格,也即输入的数据的下标);
然后进行从常规的 bfs 即可;
AC代码
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <string>
#include <algorithm>
#include <queue>
#include <utility>
#include <stack>
#include <map>
#include <vector>
#include <set>
#include <iomanip>
#include <unordered_map>
#include <deque>
#define hz020 return
#define mes memset
#define mec memcpy
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll,ll> PII;
const double pi = acos(-1);
const int N = 510;
const int null = 0x3f3f3f3f,INF = 1e9;
const ll mod = 998244353;
int T;
int n, m;
char g[N][N];
int dist[N][N];
bool st[N][N];
int bfs()
{
mes(dist, 0x3f, sizeof dist);
mes(st, false, sizeof st);
dist[0][0] = 0;
deque<pii> q;
q.push_back({0, 0});
int dx[] = {-1, -1, 1, 1}, dy[] = {-1, 1, 1, -1};
int ix[] = {-1, -1, 0, 0}, iy[] = {-1, 0, 0, -1};
while (q.size())
{
auto t = q.front();
q.pop_front();
int x = t.x, y = t.y;
if (x == n && y == m) return dist[n][m];
if(st[x][y]) continue;
st[x][y] = true;
char qq[5] = "\\/\\/";
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a > n || b < 0 || b > m) continue;
int ga = x + ix[i], gb = y + iy[i];
int w = (g[ga][gb] != qq[i]);
int d = dist[x][y] + (g[ga][gb] != qq[i]);
if (d < dist[a][b])
{
dist[a][b] = d;
if (w) q.push_back({a, b});
else q.push_front({a, b});
}
}
}
}
int main()
{
cin >> T;
while (T --)
{
cin >> n >> m;
for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);
if (n + m & 1) puts("NO SOLUTION");
else printf("%d\n", bfs());
}
hz020 0;
}