一道比较基础的图遍历的题。
思路很巧妙,要考虑到反向建图,反向BFS,找出能达到终点的点1,再正向遍历,找到这些点1中出边点均能到终点的所有点2,然后再从起点遍历,只所有2类点中找最短路径
一开始总是TLE,后来发现是初始化建图时候没有考虑到重复操作,同一个点被处理了多次,时间耗时大大降低,见代码中关键优化一段
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;
queue<int> qNode;
int n, m,x,y,s ,t;
vector<int> fwd[10005],rvs[10005];
int iCanReach[10005];
int iAllCan[10005] = { 0 };
int dis[10005];
inline int read()
{
int x = 0, y = 1; char c = getchar();
while (c>'9' || c<'0'){ if (c == '0')y = -1; c = getchar(); }
while (c >= '0'&&c <= '9'){ x = x * 10 + c - '0'; c = getchar(); }
return x*y;
}
int main()
{
n = read();
m = read();
for (int i = 0; i < m; ++i)
{
x = read();
y = read();
if (x == y)continue;
fwd[x].push_back(y);
rvs[y].push_back(x);
}
s = read();
t = read();
qNode.push(t);
while (!qNode.empty())
{
int node = qNode.front();
qNode.pop();
int isize = rvs[node].size();
for (int it = 0; it < isize; ++it)
{
int num = rvs[node][it];
if (!iCanReach[num])//关键的优化
{
qNode.push(num);
iCanReach[num] = 1;
}
}
}
if (!iCanReach[s])
{
cout << -1;
return 0;
}
iCanReach[t] = 1;
for (int j = 1; j <= n; ++j)
{
if (iCanReach[j])
{
int isize = fwd[j].size();
int it = 0;
iAllCan[j] = 1;
for (; it < isize; ++it)
{
if (!iCanReach[fwd[j][it]])
{
iAllCan[j] = 0;
break;
}
}
}
}
if (!iAllCan[s])
{
cout << -1;
return 0;
}
qNode.push(s);
dis[s] = 0;
while (!qNode.empty())
{
int node = qNode.front();
qNode.pop();
if (node == t)
{
cout << dis[t];
return 0;
}
int isize = fwd[node].size();
for (int it = 0; it <isize; ++it)
{
int itemp = fwd[node][it];
if (iAllCan[itemp] && !dis[itemp])
{
qNode.push(itemp);
dis[itemp]=dis[node] + 1;
}
}
}
return 0;
}