题目大意
有n个城市,有m对城市通火车,其他的城市间通汽车。不管是火车还是汽车,从一个城市到另一个城市的用时都为一小时。一个城市不允许同时有火车和汽车到达,但允许同时有火车和汽车发车。
问:从一号城市同时出发的火车和汽车,两者都到达n号城市的最短时间,无法到达输出 “-1”。
分析
这里有一个很有意思的事,一定有一种交通工具是直接连接一号城市和 n 号城市的
举个栗子:
4 2
1 3
3 4
这个题中只有两种状态,汽车和火车,我们用 0 和 1 表示这两种交通方式
上图:
很明显(1,n)没有火车直通,那么肯定是汽车直通的,现在我们就只需要找火车最短到达时间。
这就是最短路问题, 而且每条边的边权都是 1 ,直接BFS跑一遍就OK
现在有一个问题,我们如何确定是对火车路线进行BFS,还是对汽车路线进行BFS
仔细看上边的图,看到0,1我们都应该想到位运算
如果(1,n)为 0 ,是汽车直通,那么应该对火车进行BFS,火车的点都被标记为 1,也就是说需要BFS的点和(1,n)的标记是不一样的,自然的我们想到异或运算。
如果(x,y)^ (1,n)= 1, 那么(x,y)是需要进行BFS的点。
异或运算:二进制运算,简单说就是不同为 1,记住下边三个等式就OK
1 ^ 0 = 1,
1 ^ 1 = 0,
0 ^ 0 = 0
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
int n, m;
cin >> n >> m;
int x, y;
for (int i = 1; i <= m; i++) {
cin >> x >> y;
ma[x][y] = ma[y][x] = 1;
}
queue<int>q;
q.push(1); // 从一号点出发
memset(d, -1, sizeof(d)); //初始 1 号点到各点的距离为 -1
d[1] = 0;
bool flag = true;
while(!q.empty()){
int v = q.front();
q.pop();
if(v == n){ // 因为边权都为 1,所以,第一次到达 n号节点时,一定是用时最短的
cout << d[n] << endl;
flag = false;
break;
}
for(int i = 1; i <= n; i++){ //与 v 点连接的点就是下一步可以到达的点
if(ma[v][i] ^ ma[1][n]){ // 异或运算判断要走火车还是汽车
if(d[i] == -1){ // 没有到过的点加入队列中,到过的点不需要重复判断,一定是费时的
q.push(i);
d[i] = d[v] + 1;
}
}
}
}
if(flag) cout << -1 << endl; // 如果不能跑到(1,n)那就是 -1 了
return 0;
}
本来一直以为这个题要用 Dijkstra 算法写,后来发现因为边权值都为1,直接BFS就OK
哪里我说的不清楚的,欢迎留言提问