A. 寻找道路 (bfs, 最短路)

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

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

注意: 图 G G G 中可能存在重边和自环,保证终点没有出边。
请你输出符合条件的路径的长度。
Input Data
第一行有两个用一个空格隔开的整数 n n n m m m ,表示图有 n n n 个点和 m m m 条边。
接下来的 m m m 行每行 2 个整数 x 、 y x 、 y xy ,之间用一个空格隔开,表示有一条边从点 x x x 指向点 y y y 。 最后一行有两个用一个空格隔开的整数 s 、 t s 、 t st ,表示起点为 s s s ,终点为 t t t
Output Data
输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出 -1
Sample Input 1
3 2
1 2
2 1
1 3
Sample Output 1
-1
Sample Input 2
6 6
1 2
1 3
2 6
2 5
4 5
3 4
1 5
Sample Output 2
3
在这里插入图片描述
样例1如上图所示,箭头表示有向道路,圆点表示城市。起点 1 与终点 3 不连通,所以满足题目描述的路径不存在,故输出-1。
在这里插入图片描述
样例2如上图所示,满足条件的路径为 1 → 3 → 4 → 5 1 \rightarrow 3 \rightarrow 4 \rightarrow 5 1345 。注意点 2 不能在答案路径中,因为点 2 连了一条边到点 6 ,而点 6 不与终 点 5 连通。
对于 30%的数据, 0 < n ≤ 10 , 0 < m ≤ 20 0<n \leq 10,0<m \leq 20 0<n10,0<m20
对于 60%的数据, 0 < n ≤ 100 , 0 < m ≤ 2000 0<n \leq 100,0<m \leq 2000 0<n100,0<m2000
对于 100%的数据, 0 < n ≤ 10 , 000 , 0 < m ≤ 200 , 000 , 0 < x , y , s , t ≤ n , x ≠ t 0<n \leq 10,000,0<m \leq 200,000,0<x, y, s, t \leq n, x \neq t 0<n10,000,0<m200,000,0<x,y,s,tn,x=t

Tips: 本来以为是从终点开始的拓扑排序。。(只能拿10分呜呜)
其实应该是先通过终点bfs标记谁能到达终点,然后再在标记的限制之上跑Dijkstra算法求最短路。一开始想到了,但是感觉又有点简单就没写。。。以后优先写简单的算法,跑几个特殊样例没问题就交简单的想法,再不行再考虑难的算法。

Code:

struct Node {
	int w, x;
	bool operator < (const Node& rhs) const {
		return w > rhs.w;
	}
};

signed main() {
    ios::sync_with_stdio(0), cin.tie(0);

    int n, m;
    cin >> n >> m;
    vector<vector<int>> h(n + 1);
    vector<vector<Node>> g(n + 1);
    for (int i = 1; i <= m; i++) {
    	int u, v;
    	cin >> u >> v;
    	if (u == v) continue;
    	g[u].push_back(Node{1, v});
    	h[v].push_back(u);
    }
    int s, t;
    cin >> s >> t;
    queue<int> q;
    vector<int> vis(n + 1, 0), tag(n + 1, 0);
    q.push(t);
    while (!q.empty()) {
    	int u = q.front();
    	q.pop();
 		if (vis[u]) continue;
    	vis[u] = 1;
    	for (auto v : h[u]) {
    		q.push(v);
    	}
    }

    priority_queue<Node> tq;
    tq.push(Node{0, s});
    vector<int> dis(n + 1, INT_MAX), vit(n + 1, 0);
    dis[s] = 0;
    while (!tq.empty()) {
    	int x = tq.top().x;
    	tq.pop();
    	if (vit[x]) continue;
    	vit[x] = 1;
    	tag[x] = 1;
    	for (auto p : g[x]) {
    		int y = p.x;
    		if (!vis[y]) {
    			tag[x] = 0;
    		}
    	}
    	if (!tag[x]) continue;

    	for (auto p : g[x]) {
    		int y = p.x, z = p.w;
    		if (dis[y] > dis[x] + z) {
    			dis[y] = dis[x] + z;
    			if (!vit[y]) {
    				tq.push(Node{dis[y], y});
    			}
    		}
    	}
    }
    
    cout << (dis[t] == INT_MAX ? -1 : dis[t]) << "\n";
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值