Link
解题思路
ybtoj的数据太水了,方法一luogu那根本过不去
将 n n n * m m m的格子图,换成 ( n + 1 ) (n+1) (n+1) * ( m + 1 ) (m+1) (m+1)的点图(?反正就是一个格子四个点)
一个点连向其他点有四种路
一个点到另一个点的路,假设和初始路不同,边权为1,相同为0
比如这个就是, l e n [ i ] [ j + 1 ] [ 3 ] = 1 len[i][j+1][3] = 1 len[i][j+1][3]=1, ( i , j + 1 ) (i,j+1) (i,j+1)走到 ( i + 1 , j ) (i+1,j) (i+1,j)路为3,但是此条边是0或2
所以 ( i , j + 1 ) (i,j+1) (i,j+1)走路3到(i+1,j) 的边权为1(即 l e n [ i ] [ j + 1 ] [ 3 ] = 1 len[i][j+1][3] = 1 len[i][j+1][3]=1)
其他同理
从左上角开始走最短路,走到右下角
普通最短路一定会T掉qwq
据luogu大佬博客所说:dijstra+堆优化、SPFA+…一堆我看不懂不知道的东西,是可以过得
但是,蒟蒻选择打 广搜 + 双端队列
双端队列
普通的队列是从队尾插入的,队头弹出的
但是双端队列可以从队头插入,对尾弹出
- 定义
#include <queue>
using namespace std;
deque<int>q
- 队头
q.push_front(a); //队头插入
q.front(); //队头
q.pop_front(); //弹出队头
- 队尾
q.push_back(b); //队尾插入
q.back(); //队尾
q.pop_back(); //弹出队尾
- 其他
q.size() //返回队列长度
q.empty(); //如果队列为空,返回true,否则返回false
q.clear(); //清空队列
过程中需要加入最短路松弛
则判断能不能入队时,除了判断当前点在不在队列中,还必须是可以松弛(这样入队后才可能会对答案有贡献)
如果先做优的点,松弛出来的边就可能更优,松弛操作和入队操作就可能变少(就是操作变少,速度变快)
欸,这个时候双端队列就有作用了
两点之间边权为0,则将点从队头入队;两点之间边权为1,则将点从队尾入队
尽量做边权为0的边,松弛可能更优
Code
#include <iostream>
#include <utility>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
using namespace std;
const int way[4][2] = {
{
-1, -1}, {
-1, 1}, {
1, 1}, {
1, -1}};
pair<int, int> now;
deque<pair<int, int> >q;
int T, n, m, xx, yy, dis[510][510], v[510][510], len[510][510][4];
char c;
void init() {
memset(v, 0, sizeof(v));
memset(len, 0, sizeof(len));
memset(dis, 0x7f, sizeof(dis));
q.clear();
}
bool check(int x, int y) {
return (x > 0 && x <= n && y > 0 && y <= m); }
void BFS() {
v[1][1] = 1;
dis[1][1] = 0;
q.push_front(make_pair(1, 1));
while(!q.empty()) {
now = q.front();
v[now.first][now.second] = 0;
q.pop_front();
for (int i = 0; i < 4; i++) {
xx = now.first + way[i][0], yy = now.second + way[i][1];
if (!check(xx, yy)) continue;
if (!len[now.first][now.second][i]) {
//不需要翻转(边权为0)
if (dis[xx][yy] > dis[now.first][now.second]) {
//松弛
dis[xx][yy] = dis[now.first][now.second];
if (!v[xx][yy]) {
q.push_front(make_pair(xx, yy));//从队头加入
v[xx][yy] = 1;
}
}
} else {
if (dis[xx][yy] > dis[now.first][now.second] + 1) {
dis[xx][yy] = dis[now.first][now.second] + 1;
if (!v[xx][yy]) {
q.push_back(make_pair(xx, yy));//边权为1从队尾加入
v[xx][yy] = 1;
}
}
}
}
}
if (dis[n][m] != dis[0][0])
printf("%d\n", dis[n][m]);
else
printf("NO SOLUTION\n");
}
int main() {
// scanf ("%d", &T);
// while (T--) {
scanf ("%d%d", &n, &m);
//init();//luogu里是一组数据,ybtoj里是多组数据
memset(dis, 0x7f, sizeof(dis));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
cin >> c;
if (c == '/')
len[i][j][2] = len[i + 1][j + 1][0] = 1;//需要翻转
else
len[i][j + 1][3] = len[i + 1][j][1] = 1;
}
n++, m++;
BFS();
// }
}