• 寻找道路


    【问题述】

    在有向图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】

    road.in

    road.out

    3 2

    1 2

    2 1

    1 3

    -1

     

     

    【输入输出样例说明】

     

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

     

    【输入输出样例2】

    road.in

    road.out

    6 6

    1 2

    1 3

    2 6

    2 5

    4 5

    3 4

    1 5

    3

     

    【输入输出样例说明】

     

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


     思路:

    说实话,我一开始没想到用广搜,以为就是一道基本的图论题,这道题告诉我们,有时候逆向思维很重要

    因为我们要建反边,从终点倒着遍历一遍,打上标记,表明是可以到达终点的点

    再枚举一遍,找出所有没打标记的点,这些点的扩展如果打上标记,我们就需要清除掉,因为已经不符合题目条件

    最后再倒着遍历一遍,就可以更新出答案啦

    代码:(打“//” 说明易错哦)

    #include<stdio.h>
    #include<string.h> 
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    const int M=10001,X=200001;
    vector<int> edge[M];
    queue<int> q;
    int n,m,st,ed,ans[M];
    bool vis[X],upd[X];
    
    int main()
    {
        scanf("%d%d",&n,&m); 
        for(int i=1;i<=m;++i)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            if(u==v) continue;
            edge[v].push_back(u);
        }
        scanf("%d%d",&st,&ed);
        vis[ed]=1; //
        q.push(ed);
        while(!q.empty())
        {
            int cur=q.front();
            q.pop();
            for(int i=0;i<edge[cur].size();++i) //
            {
                int next=edge[cur][i];
                if(!vis[next]) 
                {
                    vis[next]=1;
                    q.push(next);
                }
            }
        }
        memcpy(upd,vis,sizeof(vis));
        for(int i=1;i<=n;++i) 
            if(!vis[i]) 
                for(int j=0;j<edge[i].size();++j)
                {
                    int next=edge[i][j];
                    if(upd[next]) {
                        upd[next]=0; //
                    }
                }
        q.push(ed);
        while(!q.empty())
        {
            int cur=q.front();
            q.pop();
            for(int i=0;i<edge[cur].size();++i)
            {
                int next=edge[cur][i];
                if(upd[next]) 
                {
                    q.push(next); //
                    upd[next]=0;
                    ans[next]=ans[cur]+1;
                }
            }
        }
        if(!ans[st]) printf("-1");
        else printf("%d",ans[st]);
        return 0;
    }
    从0到1很难,但从1到100很容易
  • 相关阅读:
    poj 3070 矩阵快速幂模板
    poj3207 2-SAT入门
    poj 3683 2-SAT入门
    2-SAT开坑
    poj 1442 名次树
    hdu 3068 最长回文子串 TLE
    poj 3261 二分答案+后缀数组 求至少出现k次的最长重复子序列
    poj 1743 二分答案+后缀数组 求不重叠的最长重复子串
    后缀数组笔记
    poj2774 后缀数组 求最长公共子串
  • 原文地址:https://www.cnblogs.com/qseer/p/9618792.html
Copyright © 2020-2023  润新知