NOIP2014 寻找道路

题目描述 Description

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

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

2.在满足条件1的情况下使路径最短。

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

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

 

输入描述 Input Description

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

接下来的m行每行2个整数x、y,之间用一个空格隔开,表示有一条边从点x指向点y。

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

 

输出描述 Output Description

输出文件名为road.out。

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

样例输入 Sample Input

road.in

road.out

3 2

1 2

2 1

1 3

-1

样例输出 Sample Output

road.in

road.out

6 6

1 2

1 3

2 6

2 5

4 5

3 4

1 5

3

数据范围及提示 Data Size & Hint

对于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。

思路:

分析问题,做的最短路中的点既能从起点出发,又能从终点回来,所以先预处理,有两种方式,可以先在起点进行一遍bfs,把在没到终点前就没有出边的点标记下,然后再沿着反图进行一遍bfs,或者可以直接从终点出发在反图进行一遍bfs,把没涉及到的点标出来,然后再在反图bfs,最后最短路

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>

using namespace std;

const int maxn = 200005,maxnum = 100000;
int dist[maxn],jud[maxn],q[maxn],start[maxn],tnum[maxn],fjud[maxn],cuter[maxn],n,m,x,t,ans,num = 0;

struct star{
    int next;
    int to;
    int p;
};
star edge[maxn];

void dfs(int node){
    int head = 1,tail = 1,bq[maxn];
    fjud[node] = 0;
    bq[1] = node;
    while(head <= tail){
        int now = bq[head];
        for(int i = start[now];i != -1;i = edge[i].next){
            if(fjud[edge[i].to]){
                tail = (tail + 1) % maxn;
                bq[tail] = edge[i].to;
                fjud[edge[i].to] = 0;
            }
        }
        head = (head + 1) % maxn;
    }
}

void dfs1(int node){
    int head = 1,tail = 1,bq[maxn];
    cuter[node] = 0;
    bq[1] = node;
    while(head <= tail){
        int now = bq[head];
        for(int i = start[now];i != -1;i = edge[i].next){
            if(cuter[edge[i].to]){
                bq[tail] = edge[i].to;
                cuter[edge[i].to] = 0;
            }
        }
        head = (head + 1) % maxn;
    }
}

int spfa(int u,int v){
    dist[u] = jud[u] = 0;
    q[1] = u;
    int head = 1,tail = 1;
    while(head <= tail){
        int now = q[head];
        for(int i = start[now];i != -1;i = edge[i].next){
        
            if(dist[edge[i].to] > dist[now] + edge[i].p && cuter[edge[i].to]){
                dist[edge[i].to] = dist[now] + edge[i].p;
                if(jud[edge[i].to]){
                tail = (tail + 1) % maxn;
                q[tail] = edge[i].to;
                jud[edge[i].to] = 0;
                }
            }
        }
        
        head = (head + 1) % maxn;
        jud[now] = 1;
    }
    if(dist[v] == 100000) return -1;
    return dist[v];
}

int main(){
    cin>>n>>m;
    int u,v,p;
    for(int i = 1;i <= n;i++){
        start[i] = -1;
        dist[i] = maxnum;
        jud[i] = 1;
        fjud[i] = 1;
        cuter[i] = 1;
        tnum[i] = 0;
        
    }
    int cnt = 1;
    for(int i = 1;i<= m;i++){
        cin>>u>>v;
        swap(u,v);
        edge[i].p = 1;
        edge[i].to = v;
        edge[i].next=start[u];
        cnt++;
        start[u] = cnt - 1;
        tnum[u]++; 
    }
    cin>>x>>t;
    dfs(t);
    for(int i = 1;i <= n;i++) if(fjud[i]) dfs1(i);
    cuter[x]= cuter[t] = 1;
    ans = spfa(t,x);
    cout<<ans;
    return 0;
}

 

posted @ 2016-08-27 11:09  ACforever  阅读(224)  评论(0编辑  收藏  举报