[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<n100<n≤10,0<m200<m≤20;

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

对于100%的数据,0<n100000<n≤10000,0<m2000000<m≤200000,0<x,y,s,tn0<x,y,s,t≤n,x,stx,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 }
死于细节

 

posted @ 2017-08-16 15:19  μSsia  阅读(250)  评论(0编辑  收藏  举报