版权声明: https://blog.csdn.net/leelitian3/article/details/82623689
写在前面
写博客之前搜索了一下网解,发现大家都是BFS+三维vis过的:CCF201604-4 游戏(100分)
这里分享一个BFS+优先队列的满分思路(如有错误请指正)
大致思路
每次从队列中找出d值最小的结点, 假设为u,由于使用的是优先队列,那么能够保证每次出队的u是最优的先驱。那么对于它的邻接结点v,有:
①若v在u.d+1的时间可达,那么v.d = u.d+1,且这是它的最短路径;
②若不可达(即v.begin ≤ u.d+1 ≤ v.end),那么就要等待一会让其过了危险时间v.end,等待期间需要来回踱步:
若等待时间为奇数,那么v.d = v.end+1
若为偶数则为v.end+2
由于u.d是最先到达v附近的时间,所以此时v.d也是最短路径。
C++满分代码(带注释)
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
struct Node
{
int x, y, d;
Node(int a,int b,int c):x(a),y(b),d(c) {}
bool friend operator < (const Node& a, const Node& b)
{
return a.d > b.d;
}
};
int n,m,t,r,c,a,b;
int start[105][105]; //不能经过时间段的起始时间
int stop[105][105]; //不能经过时间段的终止时间
int d[105][105]; //每个点到源节点的最短路径
bool vis[105][105]; //是否已经确定了最短路径
priority_queue<Node> que; //优先队列
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; //方向
bool is_legal(int x, int y) //判断是否越界或者已经被找到最短路径
{
if(vis[x][y] == 1) return 0;
if(x <= 0 || x > n || y <= 0 || y > m) return 0;
return 1;
}
void bfs()
{
int x, y, r, c, dis;
que.push(Node(1,1,0));
vis[1][1] = 1;
while(!que.empty())
{
x = que.top().x; //每次找到d值最小的结点bfs
y = que.top().y;
que.pop();
// cout<<"("<<x<<","<<y<<"): "<<d[x][y]<<"\n";
for(int i=0; i<4; ++i)
{
r = x + dir[i][0]; //邻接的结点
c = y + dir[i][1];
if(is_legal(r,c) == 0) continue;
dis = d[x][y] + 1;
if(start[r][c] !=0 && stop[r][c] != 0 && dis >= start[r][c] && dis <= stop[r][c]) //如果不能经过
{
if((stop[r][c] - dis) & 1) dis = stop[r][c] + 1; //来回踱步,如果要踱步奇数次,那么时间为stop[r][c] + 1时就可以到达
else dis = stop[r][c] + 2; //偶数次,就要多走一步
}
vis[r][c] = 1;
d[r][c] = dis;
que.push(Node(r,c,dis)); //加入队列
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>t;
while(t--)
{
cin>>r>>c>>a>>b;
start[r][c] = a;
stop[r][c] = b;
}
memset(d,0x3f3f3f3f,sizeof(d)); //设为无穷大
d[1][1] = 0;
bfs();
cout<<d[n][m];
return 0;
}