洛谷 P2296 寻找道路(最短路) 题解
题目来源:
https://www.luogu.org/problemnew/show/P2296
题目描述:
题目描述
在有向图 GG 中,每条边的长度均为 11,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
- 路径上的所有点的出边所指向的点都直接或间接与终点连通。
- 在满足条件11的情况下使路径最短。
注意:图 GG 中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
输入输出格式
输入格式:
第一行有两个用一个空格隔开的整数 nn 和 mm,表示图有 nn 个点和 mm 条边。
接下来的 mm 行每行 22 个整数 x,yx,y,之间用一个空格隔开,表示有一条边从点 xx 指向点yy。
最后一行有两个用一个空格隔开的整数 s, ts,t,表示起点为 ss,终点为 tt。
输出格式:
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出-1−1。
输入输出样例
输入样例#1: 复制
3 2 1 2 2 1 1 3
输出样例#1: 复制
-1
输入样例#2: 复制
6 6 1 2 1 3 2 6 2 5 4 5 3 4 1 5
输出样例#2: 复制
3
说明
解释1:
如上图所示,箭头表示有向道路,圆点表示城市。起点11与终点33不连通,所以满足题目描述的路径不存在,故输出-1−1 。
解释2:
如上图所示,满足条件的路径为11- >33- >44- >55。注意点22 不能在答案路径中,因为点22连了一条边到点66 ,而点66不与终点55 连通。
【数据范围】
对于30\%30%的数据,0 < n \le 100<n≤10,0 < m \le 200<m≤20;
对于60\%60%的数据,0 < n \le 1000<n≤100,0 < m \le 20000<m≤2000;
对于100\%100%的数据,0 < n \le 10000, 0 < m \le 200000,0 < x,y,s,t \le n, x,s \ne t0<n≤10000,0<m≤200000,0<x,y,s,t≤n,x,s≠t。
解题思路:
本身就是一个最短路,但是因为对最短路径上的点有限制,所以麻烦一点,我先反向建边,处理出终点可以到的点,然后在处理每一个点的出边能否到终点,然后只要在求最短路的时候判断能不能使用就行。。
代码:
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn=2*1e5+10;
int n,m,head[10010],vis[10010],dis[10010],pd[10010],jl[10010],cnt=0,S,T;
struct newtt
{
int from,to,cost;
}edge[maxn];
struct newt
{
int to,next,cost;
}e[maxn];
void addedge(int u,int v,int w)
{
e[cnt].to=v;
e[cnt].cost=w;
e[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int u)
{
pd[u]=1;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(!pd[v])dfs(v);
}
return;
}
void cl(int u)
{
vis[u]=1;
int flag=1;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(!pd[v])flag=0;
if(!vis[v])cl(v);
}
jl[u]=flag;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)head[i]=-1;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&edge[i].from,&edge[i].to);
if(edge[i].from==edge[i].to)continue;
addedge(edge[i].to,edge[i].from,1);
}
scanf("%d%d",&S,&T);
dfs(T);
//for(int i=1;i<=n;i++)printf("%d\n",pd[i]);
for(int i=1;i<=n;i++)head[i]=-1,dis[i]=1e9;
cnt=0;
for(int i=1;i<=m;i++)
addedge(edge[i].from,edge[i].to,1);
for(int i=1;i<=n;i++)
if(!vis[i])cl(i);
for(int i=1;i<=n;i++)vis[i]=0;
queue<int>q;
vis[S]=1;
q.push(S);
dis[S]=0;
while(!q.empty())
{
int now=q.front();q.pop();
vis[now]=0;
for(int i=head[now];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(!jl[v])continue;
if(dis[v]>dis[now]+e[i].cost)
{
dis[v]=dis[now]+e[i].cost;
if(vis[v])continue;
vis[v]=1;
q.push(v);
}
}
}
// for(int i=1;i<=n;i++)printf("%d %d\n",pd[i],jl[i]);
if(dis[T]==1e9)puts("-1");
else printf("%d\n",dis[T]);
return 0;
}
上一篇: 【最短路】P2296 寻找道路
下一篇: Linux基础命令集合