寻找道路
链接:https://ac.nowcoder.com/acm/problem/16498
题目描述
在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
1.路径上的所有点的出边所指向的点都直接或间接与终点连通。
2.在满足条件1的情况下使路径最短。
注意:图G中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
输入描述:
第一行有两个用一个空格隔开的整数n和m,表示图有n个点和m条边。
接下来的m行每行2个整数x、y,之间用一个空格隔开,表示有一条边从点x指向点y。
最后一行有两个用一个空格隔开的整数s、t,表示起点为s,终点为t。
输出描述:
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出-1。
示例1
输入
3 2
1 2
2 1
1 3
输出
-1
如上图所示,箭头表示有向道路,圆点表示城市。起点1与终点3不连通,所以满足题目描述的路径不存在,故输出-1。
示例2
输入
6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5
输出
3
如上图所示,满足条件的路径为1->3->4->5。注意点2不能在答案路径中,因为点2连了一条边到点6,而点6不与终点5连通。
备注:
对于30%的数据,0< n≤10,0< m≤20;
对于60%的数据,0< n≤100,0< m≤2000;
对于100%的数据,0< n≤10,000,0< m≤200,000,0< x,y,s,t≤n,x≠t。
解题思路
一个有向图求最短路径前提是 : 经过该路径的点必须都直接或间接指向终点
所以我们先反向建图从终点搜索到起点,然后标记该路径上的点
然后再一次搜索,从起点搜索到终点,路径上没加一个点就枚举该点下面连接的点,如果该点状态没有被标记,则这个点不计入路径
错误代码
#include <bits/stdc++.h>
using namespace std;
template<class T>inline void read(T &res){
char c;T flag=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
const int N = 1e4 + 10;
const int M = 2e5 + 10;
int n,m;
int h[N],e[M],ne[M],idx;
int s,t;
bool check[N];
int dis[N];
queue<int > q;
int a[M * 2];
void add(int a,int b){
e[idx] = b;ne[idx] = h[a];h[a] = idx++;
}
int main(){
read(n);read(m);
memset(h, -1, sizeof h);
memset(dis,-1,sizeof dis);
for(int i = 0;i < m * 2;i ++) read(a[i]);
for(int i = 0;i < m;i ++) add(a[i * 2 + 1],a[i * 2]);
read(s);read(t);
q.push(t);
check[t] = true;
while(!q.empty()){
int t = q.front();
q.pop();
for(int i = h[t];i != -1;i = ne[i]){
int j = e[i];
if(check[j] == true) continue;
check[j] = true;
q.push(j);
}
}
memset(h, -1, sizeof h);
memset(e,0,sizeof e);
memset(ne,0,sizeof ne);
idx = 0;
for(int i = 0;i < m;i ++) add(a[i * 2],a[i * 2 + 1]);
q.push(s);
while(!q.empty()){
int t = q.front();
q.pop();
for(int i = h[t];i != -1;i = ne[i]){
int j = e[i];
if(check[j] == false){
check[t] = false;
continue;
}
q.push(j);
}
}
q.push(s);
dis[s] = 0;
while(!q.empty()){
int t = q.front();
q.pop();
for(int i = h[t];i != -1;i = ne[i]){
int j = e[i];
if(check[j] == true && dis[j] == -1){
dis[j] = dis[t] + 1;
q.push(j);
}
}
}
if(dis[t] == -1) cout << "-1" << endl;
else cout << dis[t] << endl;
return 0;
}
AC代码
#include <bits/stdc++.h>
using namespace std;
#define IOS std::ios::sync_with_stdio(false);std::cin.tie(0);
const int N = 1e4 + 10, M = 2e5 + 10;
int n, m;
int h[N], e[M], ne[M], idx;
int h1[N], e1[M], ne1[M], idx1;
int state[N], dis[N]; // state[i]=true代表点i可以到达终点
int start, ed;
void add(int a, int b){
e[idx] = b;ne[idx] = h[a];h[a] = idx++;
}
void add1(int a, int b){
e1[idx1] = b;ne1[idx1] = h1[a];h1[a] = idx1++;
}
void bfs(int s){
queue<int> q;
q.push(s);
memset(dis, -1, sizeof dis);
dis[s] = 0;
while (!q.empty()){
int t = q.front();
q.pop();
state[t] = true;
for (int i = h1[t]; i != -1; i = ne1[i]){
int j = e1[i];
if (dis[j] == -1){
dis[j] = dis[t] + 1;
q.push(j);
}
}
}
}
int bfs1(int s){
memset(dis, -1, sizeof dis);
dis[s] = 0;
queue<int> q;
q.push(s);
while (!q.empty()){
int t = q.front();
q.pop();
for (int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
if (dis[j] == -1){
dis[j] = dis[t] + 1;
bool flag = true;
for (int k = h[j]; k != -1; k = ne[k]){
int kk = e[k];
if (state[kk] ==false){
flag = false;
break;
}
}
if (flag)
q.push(j);
if (j == ed)
return dis[ed];
}
}
}
return -1;
}
int main(){
IOS;
cin >> n >> m;
int x, y;
memset(h, -1, sizeof h);
memset(h1, -1, sizeof h1);
for (int i = 0; i < m; i++){
cin >> x >> y;
add(x, y);
add1(y, x);
}
cin >> start >> ed;
bfs(ed);
cout << bfs1(start) << '\n';
return 0;
}