–>题面
题目描述 Description
在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
1.路径上的所有点的出边所指向的点都直接或间接与终点连通。
2.在满足条件1的情况下使路径最短。
注意:图G中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
输入描述1 Input Description
第一行有两个用一个空格隔开的整数n和m,表示图有n个点和m条边。
接下来的m行每行2个整数x、y,之间用一个空格隔开,表示有一条边从点x指向点y。
最后一行有两个用一个空格隔开的整数s、t,表示起点为s,终点为t。
输出描述1 Output Description
输出文件名为road.out。
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出-1。
样例输入1 Sample Input
3 2
1 2
2 1
1 3
样例输出1 Sample Output
-1
样例输入2 Sample Input
6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5
样例输出1 Sample Output
3
数据范围及提示 Data Size & Hint
对于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。
–>分析
有2个条件嗯……第二个没啥意思 所以主要是满足第一个条件
与终点相连的点就是能走到终点的点;
也就是说 把有向边反向之后 能从终点走到的点;
所以我们再建一个反向图;
然后我们把这些能从终点走到的点标记一下;
这样那些在正向图中走不到终点的点就不会被标记;
还有一些点我们也不能走,比如样例 2 中的 2 点,因为它连了一个 被我们否点的 6 点;
所以我们在spfa 的时候 判断一下 当前的点 是否连了不该连的点,如果连了 我们不用;
这样跑出最短路来就不会有不满足条件的点了。
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
const int MAX_V = 10000 + 15;
const int MAX_E = 200000 + 15;
int V, E, Ts, Te, tot = 0, tot2 = 0;
int d[MAX_V], first[MAX_V], nxt[MAX_E << 1];
int first2[MAX_V], nxt2[MAX_E << 1];//反建图
bool spfaused[MAX_V],could[MAX_V],t[MAX_V];
struct edge{
int from, to, cost;
};
edge es[MAX_E << 1];
edge es2[MAX_E << 1];//反建图
void init()
{
memset(first,-1,sizeof(first));
memset(first2,-1,sizeof(first2));
}
void build(int ff, int tt, int dd)
{
es[++tot] = (edge){ff,tt,dd};
nxt[tot] = first[ff];
first[ff] = tot;
}
void build2(int ff, int tt, int dd)//反建图
{
es2[++ tot2] = (edge){ff,tt,dd};
nxt2[tot2] = first2[ff];
first2[ff] = tot2;
}
void findcan(int s)//寻找能到达的点并标记
{
could[s] = 1;
t[s] = 1;
for(int i = first2[s]; i != -1; i = nxt2[i])
{
int v = es2[i].to;
if(!t[v])
findcan(v);
}
}
bool cankill(int x)//是否能够被杀(不能用)
{
for(int i = first[x]; i != -1; i = nxt[i])
{
int v = es[i].to;
if(!could[v])
return true;
}
return false;
}
queue<int> q;
void spfa(int s)
{
memset(d,0x3f,sizeof(d));
d[s] = 0;
q.push(s);
spfaused[s] = 1;
while(!q.empty())
{
int x = q.front();
q.pop();
spfaused[x] = 0;
if(cankill(x))//看一下这个点是不是连了不该连的点
continue;
for(int i = first[x]; i != -1; i = nxt[i])
{
int v = es[i].to;
/*
下面可以改为 :
if(!used[v])
{
d[v] = d[x] + 1;
q.push(v);
used[v] = 1;
}
*/
if(d[v] > d[x] + es[i].cost)
{
d[v] = d[x] + es[i].cost;
if(!spfaused[v])
{
q.push(v);
spfaused[v] = 1;
}
}
}
}
}
int main()
{
init();
scanf("%d%d",&V, &E);
for(int i = 1; i <= E; i ++)
{
int x, y;
scanf("%d%d",&x,&y);
build(x,y,1);
build2(y,x,1);
}
scanf("%d%d",&Ts, &Te);
findcan(Te);
spfa(Ts);
if(d[Te] < 0x3f3f3f3f - 233)
printf("%d\n",d[Te]);
else printf("-1\n");
for(int i = 1; i <= V; i ++)
return 0;
}
K.O.