寻找道路 noip2014D2T2

66 篇文章 0 订阅
56 篇文章 0 订阅

题目描述


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

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

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

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

Solution


感觉前几年的noip都好水=_=;
题目要求的合法点我们反向bfs就可以得到了,然后新的图做一次spfa(其实边权恒为1的话bfs也行)
水题1A

Code


#include <stdio.h>
#include <string.h>
#include <vector>
#include <queue>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define erg(i, now) for (int i = ls[now]; i; i = e[i].next)
#define fill(x, t) memset(x, t, sizeof(x))
#define pb push_back
#define N 100001
#define E N * 4 + 1
struct edge{int x, y, w, next;}e[E];
int inQueue[N], prt[N], dis[N], vis[N], ls[N];
inline int read(){
    int x = 0, v = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        if (ch == '-'){
            v = -1;
        }
        ch = getchar();
    }
    while (ch <= '9' && ch >= '0'){
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }
    return x * v;
}
using std:: queue;
inline void bfs(int st){
    queue<int> que;
    que.push(st);
    fill(vis, 0);
    vis[st] = 1;
    while (!que.empty()){
        int now = que.front(); que.pop();
        erg(i, now){
            if (!vis[e[i].y]){
                vis[e[i].y] = 1;
                que.push(e[i].y);
            }
        }
    }
}
inline int spfa(int st, int ed){
    queue<int> que;
    que.push(st);
    fill(dis, 63);
    dis[st] = 0;
    fill(inQueue, 0);
    inQueue[st] = 1;
    while (!que.empty()){
        int now = que.front(); que.pop();
        erg(i, now){
            if (dis[now] + e[i].w < dis[e[i].y]){
                dis[e[i].y] = dis[now] + e[i].w;
                if (!inQueue[e[i].y]){
                    inQueue[e[i].y] = 1;
                    que.push(e[i].y);
                }
            }
        }
        inQueue[now] = 0;
    }
    int ret = dis[ed];
    if (dis[ed] == dis[0]){
        ret = -1;
    }
    return ret;
}
inline void addEdge(int &cnt, int x, int y, int w){
    cnt += 1; e[cnt] = (edge){x, y, w, ls[x]}; ls[x] = cnt;
}
using std:: vector;
int main(void){
    int n = read(), m = read();
    vector<int> x, y;
    rep(i, 1, m){
        x.pb(read());
        y.pb(read());
    }
    int st = read(), ed = read();
    int edgeCnt = 0; fill(ls, 0);
    rep(i, 0, x.size() - 1){
        addEdge(edgeCnt, y[i], x[i], 1);
    }
    bfs(ed);
    edgeCnt = 0; fill(ls, 0);
    rep(i, 0, x.size() - 1){
        addEdge(edgeCnt, x[i], y[i], 1);
    }
    rep(now, 1, n){
        bool flag = true;
        erg(i, now){
            if (!vis[e[i].y]){
                flag = false;
                break;
            }
        }
        if (flag){
            prt[now] = 1;
        }
    }
    edgeCnt = 0; fill(ls, 0);
    rep(i, 0, x.size() - 1){
        if (prt[x[i]] && prt[y[i]]){
            addEdge(edgeCnt, x[i], y[i], 1);
        }
    }
    int ans = spfa(st, ed);
    printf("%d\n", ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值