• AC日记——寻找道路 洛谷 P2296


    题目描述

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

    1 .路径上的所有点的出边所指向的点都直接或间接与终点连通。

    2 .在满足条件1 的情况下使路径最短。

    注意:图G 中可能存在重边和自环,题目保证终点没有出边。

    请你输出符合条件的路径的长度。

    输入输出格式

    输入格式:

    输入文件名为road .in。

    第一行有两个用一个空格隔开的整数n 和m ,表示图有n 个点和m 条边。

    接下来的m 行每行2 个整数x 、y ,之间用一个空格隔开,表示有一条边从点x 指向点y 。

    最后一行有两个用一个空格隔开的整数s 、t ,表示起点为s ,终点为t 。

    输出格式:

    输出文件名为road .out 。

    输出只有一行,包含一个整数,表示满足题目᧿述的最短路径的长度。如果这样的路径不存在,输出- 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:

    如上图所示,箭头表示有向道路,圆点表示城市。起点1 与终点3 不连通,所以满足题

    目᧿述的路径不存在,故输出- 1 。

    解释2:

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

    思路:

      存边的时候正反存

      反边来dfs找终点能到的点(能到终点的点)

      然后在把出边的点能到终点的点标记为true

      然后一遍建立在true的点上的spfa

      输出最短路

      轻松ac

    来,上代码:

    #include <queue>
    #include <cstdio>
    
    #define INF 0x7ffffff
    
    using namespace std;
    
    struct node {
        int from,to,dis,next;
    };
    struct node edge[200001],edge_[200001];
    
    int n,m,head_[10001],head[10001],s,t,num=0,dis[10001];
    
    bool if_[10001],can[10001];
    
    inline void edge_add(int from,int to,int dis_)
    {
        num++;
        edge[num].to=to;
        edge[num].dis=dis_;
        edge[num].from=from;
        edge[num].next=head[from];
        head[from]=num;
        edge_[num].from=to;
        edge_[num].to=from;
        edge_[num].dis=dis_;
        edge_[num].next=head_[to];
        head_[to]=num;
    }
    
    void search(int now)
    {
        if_[now]=true;
        for(int i=head_[now];i;i=edge_[i].next)
        {
            if(!if_[edge_[i].to]) search(edge_[i].to);
        }
    }
    
    void SPFA()
    {
        if(!can[s]) return;
        queue<int>que;
        que.push(s);
        while(!que.empty())
        {
            for(int i=head[que.front()];i;i=edge[i].next)
            {
                if(can[edge[i].to])
                {
                    if(edge[i].dis+dis[que.front()]<dis[edge[i].to])
                    {
                        dis[edge[i].to]=edge[i].dis+dis[que.front()];
                        if(!if_[edge[i].to])
                        {
                            if_[edge[i].to]=true;
                            que.push(edge[i].to);
                        }
                    }
                }
            }
            if_[que.front()]=false;
            que.pop();
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        int from,to;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&from,&to);
            edge_add(from,to,1);
        }
        scanf("%d%d",&s,&t);
        search(t);
        bool if_break;
        for(int i=1;i<=n;i++)
        {
            if_break=false;
            if(!if_[i]) continue;
            for(int j=head[i];j;j=edge[j].next)
            {
                if(!if_[edge[j].to])
                {
                    if_break=true;
                    break;
                }
            }
            if(if_break) continue;
            can[i]=true;
        }
        for(int i=1;i<=n;i++) dis[i]=INF,if_[i]=false;
        dis[s]=0,if_[s]=true;
        SPFA();
        if(dis[t]>=200005) printf("-1
    ");
        else printf("%d
    ",dis[t]);
        return 0;
    }
  • 相关阅读:
    堆排序回顾
    动画函数封装
    mouseenter 和mouseover的区别
    元素滚动 scroll 系列
    元素可视区 client 系列
    元素偏移量 offset 系列
    JS执行机制
    BOM
    常用键盘事件
    常用鼠标事件
  • 原文地址:https://www.cnblogs.com/IUUUUUUUskyyy/p/6219108.html
Copyright © 2020-2023  润新知