[UOJ] #19 寻找道路

#19. 寻找道路NOIP2014

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

  1. 路径上的所有点的出边所指向的点都直接或间接与终点连通。
  2. 在满足条件 1 的情况下使路径最短。

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

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

输入格式

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

接下来的 mm 行每行 22 个整数 x,yx,y,之间用一个空格隔开,表示有一条边从点 xx 指向点yy。

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

输出格式

输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出−1−1。

样例一

input

3 2
1 2
2 1
1 3

output

-1

explanation

起点11与终点33不连通,所以满足题目描述的路径不存在,故输出−1−1。

样例二

input

6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5

output

3

explanation

注意点22不能在答案路径中,因为点22连了一条边到点66,而点66不与终点55连通。

限制与约定

对于30%的数据,0<n≤100<n≤10,0<m≤200<m≤20;

对于60%的数据,0<n≤1000<n≤100,0<m≤20000<m≤2000;

对于100%的数据,0<n≤100000<n≤10000,0<m≤2000000<m≤200000,0<x,y,s,t≤n0<x,y,s,t≤n,x,s≠tx,s≠t。

时间限制:1s1s

内存限制:128MB

分析

本来思路是 “反向存图+终点SPFA+额外判断” 求合法点集,然后 “起点SPFA” 求最短路。

结果一波挂残,20分 = =

后来决定用终点做根朴素DFS判断合法点集,再次20分 = =

关键在合法点集,根据样例合法点集内的点每一条出边都需要能到达终点,那么像样例2中的结点2是不能包括进合法点集的,此处需要注意实现部分。

代码

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #define maxn 500000
  5 using namespace std;
  6
  7 struct edge{
  8     int from,v;
  9 }e[maxn],e1[maxn];
 10
 11 const int inf = 999999999;
 12
 13 int n,m,a,b,que[maxn*100],head,tail,s,t,dis[maxn];
 14 bool book[maxn],chose[maxn];
 15 int tot,tot1,first[maxn],first1[maxn];
 16 void insert(int u,int v){
 17     tot++;
 18     e[tot].from = first[u];
 19     e[tot].v = v;
 20     first[u] = tot;
 21 }
 22
 23 void insert1(int u,int v){
 24     tot1++;
 25     e1[tot1].from = first1[u];
 26     e1[tot1].v = v;
 27     first1[u] = tot1;
 28 }
 29
 30 void dfs(int now){
 31     for(int i = first1[now];i;i = e1[i].from){
 32         int v = e1[i].v;
 33         if(!book[v]){
 34             book[v] = true;
 35             dfs(v);
 36         }
 37     }
 38 }
 39
 40 void PRINT(){
 41     printf("#dis:  ");
 42     for(int i = 1;i <= n;i++) printf("%d ",dis[i]);
 43     cout << endl;
 44 }
 45
 46 void SPFA(){
 47     for(int i = 1;i <= n;i++)
 48         book[i] = false,dis[i] = inf;
 49     head = tail = 0;
 50     que[head++] = s;
 51     book[s] = true;
 52     dis[s] = 0;
 53
 54 //    PRINT();
 55
 56     while(head > tail){
 57         int p = que[tail++];
 58         for(int i = first[p];i;i = e[i].from){
 59             int v = e[i].v;
 60             if(dis[v] > dis[p]+1){
 61                 dis[v] = dis[p]+1;
 62                 if(book[v]) continue;
 63                 book[v] = true;
 64                 que[head++] = v;
 65             }
 66         }book[p] = false;
 67     }
 68
 69 //    PRINT();
 70
 71     if(dis[t] < inf) printf("%d",dis[t]);
 72     else printf("-1");
 73 }
 74
 75 int main(){
 76     scanf("%d%d",&n,&m);
 77
 78     for(int i = 1;i <= m;i++){
 79         scanf("%d%d",&a,&b);
 80         insert1(b,a);
 81     }
 82
 83     scanf("%d%d",&s,&t);
 84
 85     book[t] = true;
 86     dfs(t);
 87
 88     memset(chose,true,sizeof(chose));
 89
 90     for(int i = 1;i <= n;i++){
 91         if(book[i]) continue;
 92         for(int j = first1[i];j;j = e1[j].from){
 93             int v = e1[j].v;
 94             if(!book[v] || !book[i]){
 95                 chose[v] = false;
 96             }
 97         }
 98     }
 99
100 //    cout << "----------------------------" << endl;
101     for(int i = 1;i <= n;i++){
102         if(!chose[i]) continue;
103         for(int j = first1[i];j;j = e1[j].from){
104             int v = e1[j].v;
105             if(chose[v]){
106 //                printf("%d %d\n",v,i);
107                 insert(v,i);
108             }
109         }
110     }
111
112 //    for(int i = 1;i <= n;i++){
113 //        printf("%c",chose[i]?‘T‘:‘F‘);
114 //        printf("%c ",book[i]?‘T‘:‘F‘);
115 //    }
116
117     SPFA();
118
119     return 0;
120 }

死于细节

时间: 2024-10-11 11:13:51

[UOJ] #19 寻找道路的相关文章

P2296 寻找道路

P2296 寻找道路 题目描述 在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1 .路径上的所有点的出边所指向的点都直接或间接与终点连通. 2 .在满足条件1 的情况下使路径最短. 注意:图G 中可能存在重边和自环,题目保证终点没有出边. 请你输出符合条件的路径的长度. 输入输出格式 输入格式: 输入文件名为road .in. 第一行有两个用一个空格隔开的整数n 和m ,表示图有n 个点和m 条边. 接下来的m 行每行2 个整数

[FZYZOJ 2047] [NOIP2014 D2T2] 寻找道路

[NOIP2014_D2_T2]寻找道路 时间限制:1000MS 内存限制:131072KB Description 在有向图 G 中,每条边的长度均为 1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1.路径上的所有点的出边所指向的点都直接或间接与终点连通. 2.在满足条件 1 的情况下使路径最短. 注意:图 G 中可能存在重边和自环,题目保证终点没有出边. 请你输出符合条件的路径的长度. Input Format 第一行有两个用一个空格隔开的整数 n 和 m,

【NOIP之旅】NOIP2014 day2 T2 寻找道路

2.寻找道路 (road.cpp/c/pas) [问题描述] 在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1.路径上的所有点的出边所指向的点都直接或间接与终点连通. 2.在满足条件1的情况下使路径最短. 注意:图G中可能存在重边和自环,题目保证终点没有出边. 请你输出符合条件的路径的长度. [输入] 输入文件名为road.in. 第一行有两个用一个空格隔开的整数n和m,表示图有n个点和m条边. 接下来的m行每行2个整数x.y,之间

寻找道路——呆滞大佬der最骚暴力

寻找道路 题目描述: 有点的出边所指向的点都直接或间接与终点连通. 2 .在满足条件1 的情况下使路径最短. 注意:图G 中可能存在重边和自环,题目保证终点没有出边. 请你输出符合条件的路径的长度. 输入格式: 第一行有两个用一个空格隔开的整数n 和m ,表示图有n 个点和m 条边. 接下来的m 行每行2 个整数x .y ,之间用一个空格隔开,表示有一条边从点x 指向点y . 最后一行有两个用一个空格隔开的整数s .t ,表示起点为s ,终点为t . 输出格式: 输出只有一行,包含一个整数,表示

【DFS】【图论】NOIP2014寻找道路

[NOIP2014]寻找道路 题目描述 Description 在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1.路径上的所有点的出边所指向的点都直接或间接与终点连通. 2.在满足条件1的情况下使路径最短. 注意:图G中可能存在重边和自环,题目保证终点没有出边. 请你输出符合条件的路径的长度. 输入描述 Input Description 第一行有两个用一个空格隔开的整数n和m,表示图有n个点和m条边. 接下来的m行每行2个整数x.

洛谷P2296 寻找道路==codevs3731 寻找道路

P2296 寻找道路 题目描述 在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1 .路径上的所有点的出边所指向的点都直接或间接与终点连通. 2 .在满足条件1 的情况下使路径最短. 注意:图G 中可能存在重边和自环,题目保证终点没有出边. 请你输出符合条件的路径的长度. 输入输出格式 输入格式: 输入文件名为road .in. 第一行有两个用一个空格隔开的整数n 和m ,表示图有n 个点和m 条边. 接下来的m 行每行2 个整数

洛谷——P2296 寻找道路

P2296 寻找道路 题目描述 在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1 .路径上的所有点的出边所指向的点都直接或间接与终点连通. 2 .在满足条件1 的情况下使路径最短. 注意:图G 中可能存在重边和自环,题目保证终点没有出边. 请你输出符合条件的路径的长度. 输入输出格式 输入格式: 输入文件名为road .in. 第一行有两个用一个空格隔开的整数n 和m ,表示图有n 个点和m 条边. 接下来的m 行每行2 个整数

luogu 2296 寻找道路

luogu 2296 寻找道路 题目链接:https://www.luogu.org/problemnew/show/P2296 从终点bfs或者dfs,找出所有终点能到达的点. 然后再从1到n看一下出边是否都与终点相连. 然后对于可行的边,做最短路即可. 因为这里的边权是1,所以bfs即可. CODE: #include <iostream> #include <cstdio> #include <queue> const int maxN = 20000 + 7;

LuoGuP2296寻找道路

LuoGuP2296寻找道路 简化题意 \(:\) 要求从 \(1\) 号点到 \(n\) 号点的最短路,不能走障碍点. 一个点不是障碍当且仅当它的所有出边指向的点能到达终点. 如何去判断一个点是否是障碍点呢 \(?\) 很简单,我们先做一遍逆拓扑(也就是在反图上以终点为起点做 \(bfs\)),处理出哪些点能与终点连通. 枚举每个点,遍历其所有出边指向的点,如果存在一个点与终点不连通,就把当前点标记为障碍. 最后再正向做一遍 \(bfs\) 即可. #include <algorithm>