zoukankan      html  css  js  c++  java
  • [luogu2296][寻找道路]

    直接赋题目。。。。。

     

    题目描述

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

    对于一般的这种没有权值的有向图,一般都会想到跑一边bfs,用一个数组记录花费比如我)。

    然而这道题的不同之处在于

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

     如图 按照题目中所述

        2可以到达T,3也可以到达T,但是选择路径时可以选择3,不能选择2。

        原因在于2有一个子节点为1,而1不能到达T,所以不能选择2。

    清楚了这个之后,思路基本上就有了(因为我太弱,思路可能不太完美)

    1. 首先,存图时,存一个反图,便于后边从t开始的bfs
    2. 从t开始bfs一次,找出所有能到达t的点
    3. 讲不能到达t的父节点和此节点标记为不能走
    4. 最后,从s开始bfs一次,只走能走的点,并用一个数组记录路径长

    最后附上代码

    1 #include<cstdio>
     2 #include<iostream>
     3 #include<queue>
     4 using namespace std;
     5 queue<int>q1,q2;
     6 struct node{
     7     int u,v,nxt;
     8 }a[200010],b[200010];
     9 int n,m,head1[10010],head2[10010],vis1[10010],s,t,vis2[10010],vis3[10010];
    10 int main()
    11 {
    12     scanf("%d%d",&n,&m);
    13     for(int i=1,x,y;i<=m;++i)
    14     {
    15         scanf("%d%d",&x,&y);
    16         if(x!=y)
    17         {
    18             a[i].u=x,a[i].v=y,a[i].nxt=head1[x];//用a来存正向图 
    19             head1[x]=i;
    20             b[i].u=y,b[i].v=x,b[i].nxt=head2[y];//b用来存反向图 
    21             head2[y]=i;
    22         }
    23     
    24     }
    25     scanf("%d%d",&s,&t);
    26     q2.push(t);
    27     vis2[t]=1; 
    28     while(!q2.empty())//从t开始一遍bfs,用vis2记录所有能到达t的点(因为是反图嘛) 
    29     {
    30         int qq=q2.front();
    31         q2.pop();
    32         for(int i=head2[qq];i;i=b[i].nxt)
    33         {
    34             int v=b[i].v;
    35             if(!vis2[v])
    36             {
    37                 vis2[v]=1;
    38                 q2.push(v); 
    39             }
    40         }
    41         
    42     }
    43     for(int i=1;i<=n;++i) 
    44     {
    45         vis3[i]=1;
    46     }
    47     for(int i=1;i<=m;++i)//将不能到达的节点及其父节点变为不能到达,
    48     {
    49         if(!vis2[a[i].v]) vis3[a[i].u]=vis3[a[i].v]=0;//用vis3记录(不用vis2是为了防止后效性,即前面的赋值影响后面,导致vis2全变为0) 
    50     }
    51     q1.push(s);
    52     vis1[s]=1;
    53     while(!q1.empty())//从s开始一遍bfs,
    54     {
    55         int qq=q1.front();
    56         q1.pop();
    57         for(int i=head1[qq];i;i=a[i].nxt)
    58         {
    59             int v=a[i].v;
    60             if(v==t)//搜到了t就将其路径长输出 
    61             {
    62                 printf("%d",vis1[a[i].u]);//因为vis[3]初值为1,所以此处不用+1; 
    63                 return 0;
    64             }
    65              else if(vis3[v]&&!vis1[v])//只走vis3中标记为能走的点(前边一大堆就是为了找这些点....) 
    66             {
    67              vis1[v]=vis1[a[i].u]+1;//将每个节点的路径长变为其父节点 路径长+1,因为权值都是1,这也是能用bfs而可以不用dijkstra的原因 
    68                 q1.push(v);
    69             }
    70         }
    71     }
    72     printf("-1");//如果不能到达就输出-1 
    73     return 0;//拜拜。。。。 
    74  } 

     

  • 相关阅读:
    CSS——清除浮动
    .net 多线程之线程取消
    .net 多线程临时变量
    NPOI helper
    添加学员存储过程
    SQL-sqlHelper001
    ado.net 中事务的使用
    T-SQL 事务2
    T-SQL 事务
    T-SQL 带参数存储过程
  • 原文地址:https://www.cnblogs.com/wxyww/p/8858731.html
Copyright © 2011-2022 走看看