P1649 [USACO07OCT]障碍路线Obstacle Course
N*N(1<=N<=100)方格中,’x’表示不能行走的格子,’.’表示可以行走的格子。卡门很胖,故而不好转弯。现在要从A点走到B点,请问最少要转90度弯几次?
调试日志: 左移写成右移了QAQ
Solution
正解应该是 \(bfs\) 吧, 每个状态保存 坐标, 步数, 方向, 搜索即可
偏不想正解, 哼
众所周知, 肥宅不可能来回踱步
因为 这样多了两步转向显然不优, 在前一步换个方向到只用一步
所以每个点分裂成两个点, 一个横向的一个纵向的
横向点之间连边, 权值为 \(0\) , 代表不需要转向
纵向点之间连边, 权值为 \(0\) , 代表不需要转向
自己的横向点到纵向点连边, 权值为 \(1\) , 代表转个向花费一
起点可以自由选择横向, 纵向, 到终点时状态横向纵向皆可
所以初始把横纵两种状态作为起始点, 最后看终点横纵状态那个最短路长度小即可
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define LL long long
#define REP(i, x, y) for(int i = (x);i <= (y);i++)
using namespace std;
int RD(){
int out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const int maxn = 100019,INF = 1e9 + 19;
int head[maxn],nume = 1;
struct Node{
int v,dis,nxt;
}E[maxn << 3];
void add(int u,int v,int dis){
E[++nume].nxt = head[u];
E[nume].v = v;
E[nume].dis = dis;
head[u] = nume;
}
int len;
int map[119][119], s, t;
int mx[4] = {0, 0, 1,-1};
int my[4] = {1,-1, 0, 0};
int id(int x, int y){return (x - 1) * len + y;}
bool judge(int x, int y){
if(x < 1 || x > len || y < 1 || y > len)return 0;
return 1;
}
int d[maxn];
bool inq[maxn];
void SPFA(){
queue<int>Q;
d[s << 1] = d[s << 1 | 1] = 0;
Q.push(s << 1), Q.push(s << 1 | 1);
inq[s << 1] = inq[s << 1 | 1] = 1;
while(!Q.empty()){
int u = Q.front();Q.pop();inq[u] = 0;
for(int i = head[u];i;i = E[i].nxt){
int v = E[i].v, dis = E[i].dis;
if(d[u] + dis < d[v]){
d[v] = d[u] + dis;
if(!inq[v])Q.push(v), inq[v] = 1;
}
}
}
}
int main(){
len = RD();
REP(i, 1, len)REP(j, 1, len){
int now = id(i, j);
d[now << 1] = d[now << 1 | 1] = INF;
char ss[19];
scanf("%s", ss);
if(ss[0] == '.')map[i][j] = 1;
else if(ss[0] == 'A')map[i][j] = 1, s = now;
else if(ss[0] == 'B')map[i][j] = 1, t = now;
}
REP(i, 1, len)REP(j, 1, len){
if(!map[i][j])continue;
int u = id(i, j);
add(u << 1, u << 1 | 1, 1);
add(u << 1 | 1, u << 1, 1);
REP(k, 0, 1){
int nx = i + mx[k], ny = j + my[k];
if(!judge(nx, ny) || !map[nx][ny])continue;
int v = id(nx, ny);
add(u << 1, v << 1, 0);
}
REP(k, 2, 3){
int nx = i + mx[k], ny = j + my[k];
if(!judge(nx, ny) || !map[nx][ny])continue;
int v = id(nx, ny);
add(u << 1 | 1, v << 1 | 1, 0);
}
}
SPFA();
int ans = min(d[t << 1], d[t << 1 | 1]);
if(ans == INF){puts("-1");return 0;}
printf("%d\n", ans);
return 0;
}