欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

洛谷 P2296 寻找道路(最短路) 题解

程序员文章站 2022-07-13 11:54:27
...

题目来源:

https://www.luogu.org/problemnew/show/P2296

题目描述:

题目描述

在有向图 GG 中,每条边的长度均为 11,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:

  1. 路径上的所有点的出边所指向的点都直接或间接与终点连通。
  2. 在满足条件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:

洛谷 P2296 寻找道路(最短路) 题解

如上图所示,箭头表示有向道路,圆点表示城市。起点11与终点33不连通,所以满足题目描述的路径不存在,故输出-1−1 。

解释2:

洛谷 P2296 寻找道路(最短路) 题解

如上图所示,满足条件的路径为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;
}