2296 寻找道路

2014 NOIP提高组 day2 第二题

提交次数:3

题目描述

在有向图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 #include<iostream>
 2 #include<vector>
 3 #include<queue> 
 4 #include<cstdio>
 5 using namespace std;
 6 vector<int>v[10010];
 7 vector<int>vr[10010];//反置图 
 8 int used[10010];
 9 int can[10010];//能通向终点的点 
10 queue<int>q;
11 struct node{
12     int num;
13     int step;
14 };
15 queue<node>qq;
16 
17 int main(){
18     int n, m;
19     cin>>n>>m;
20     int i;
21     for(i = 1; i <= m; i++){
22         int x, y;
23         scanf("%d%d", &x, &y);
24         v[x].push_back(y);
25         vr[y].push_back(x);
26     }
27     int s, t;
28     cin>>s>>t;
29     q.push(t);
30     can[t] = 1;
31     int k;
32     while(!q.empty()){
33         k = q.front();
34         q.pop();
35         for(i = 0; i < vr[k].size(); i++){
36             if(!can[vr[k][i]]){
37                 q.push(vr[k][i]);
38                 can[vr[k][i]] = 1;
39             }                
40         }
41     }
42     for(i = 1; i <= n; i++){
43         if(!can[i]){
44             for(int j = 0; j < vr[i].size(); j++)
45                 if(can[vr[i][j]]==1) can[vr[i][j]] = -1;
46         }
47     }
48     if(can[s]==0||can[s]==-1){
49         cout<<"-1";
50         return 0;
51     }
52     node p;
53     p.num = s; p.step = 0;
54     qq.push(p);
55     used[s] = true;
56 //    for(i = 1; i <= n; i++){
57 //        if(can[i]) cout<<i<<" ";
58 //    }
59 //    cout<<endl;
60     
61     while(!qq.empty()){
62         node k = qq.front();
63         if(k.num==t){
64             cout<<k.step;
65             break;
66         }
67         qq.pop();
68         for(i = 0; i < v[k.num].size(); i++){
69             if(!used[v[k.num][i]]&&can[v[k.num][i]]!=0&&can[v[k.num][i]]!=-1){
70                 p.num = v[k.num][i];
71                 p.step = k.step+1;
72                 qq.push(p);
73                 used[p.num] = true;
74             }
75         }
76     }
77     return 0;
78 }

备注:

两遍BFS。注意题目含义是,路径上所有点的所有出度都是可以到达终点的。因此不符合要求的点有两类,第一类是不能到达终点的点(用can[i]=0表示),第二类是直接指向不能到达终点的点(用can[i]=-1表示)。所以存一个反置图,首先从终点往回BFS,标记下能到达的点,再把不能到达的点所直接连接的点标记为-1。

犯了两个错误,第一是,这两类点必须分开表示,如果在排查第二类点的时候也赋值为0,那么在往后接着找时,这个点会被视作第一类点,所以会删掉不应该删的点。第二,忘了写used[p.num]=true,即标黄那行,因为图中可能存在环,如果不进行判重就会超时。

原文地址:https://www.cnblogs.com/fangziyuan/p/6078577.html