G. Moving to the Capital - Codeforces Round #693 (Div. 3)

这篇博客详细介绍了Codeforces Round #693 (Div. 3) 中的G题——Moving to the Capital的解题过程。题目涉及图论和最短路径问题,要求从每个城市出发,最终能距首都的最短距离。解题者使用Dijkstra算法求解,并提供了清晰的代码实现,展示了如何通过按最短路径从远到近枚举城市来优化路径。
摘要由CSDN通过智能技术生成

Codeforces Round #693 (Div. 3) G. Moving to the Capital

题目链接:https://codeforces.com/contest/1472/problem/G

题目大意

n n n个城市, m m m条单向路径,长度都为 1 1 1 d i d_i di表示从首都 1 1 1到城市 i i i的最短距离。然后就是说从城市 i i i j j j有两种行为,第一种随便用,第二种最多只能用一次。我们要求的是从每个城市出发,最终能距首都的最短距离。

解题思路

f f f表示最终结果, f [ i ] f[i] f[i]的初值等于 d [ i ] d[i] d[i]。我们按 d d d从大到小枚举城市 u u u u u u可以到达城市 v v v

那么如果 d [ u ] < d [ v ] d[u] < d[v] d[u]<d[v],则 u u u 可以直接采用行为 1 1 1到达 v v v,因为是按 d d d从大到小枚举,所以此时 f [ v ] f[v] f[v]是已知的,则可得 f [ u ] = m i n ( f [ u ] , f [ v ] ) f[u] = min(f[u], f[v]) f[u]=min(f[u],f[v])

如果 d [ u ] > = d [ v ] d[u] >= d[v] d[u]>=d[v],那么 u u u只能采取行为 2 2 2 v v v,因为已经用过行为 2 2 2,所以 v v v之后只能用 1 1 1了,即只能往 d d d增大的城市走,所以 d [ v ] d[v] d[v] 是最小值,可得 f [ u ] = m i n ( f [ u ] , d [ v ] ) f[u] = min(f[u], d[v]) f[u]=min(f[u],d[v])

Code

#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;

#define MAXN 200005


int d[MAXN], f[MAXN];
bool vis[MAXN];
vector<int> edges[MAXN], c[MAXN];

int main(void)
{
    int T; scanf("%d", &T);
    while(T--) {
        int n, m; scanf("%d%d", &n, &m);
        for(int i=0;i<=n;++i) edges[i].clear(), c[i].clear();
        for(int i=0;i<m;++i) {
            int u, v; scanf("%d%d", &u, &v);
            edges[u].push_back(v);
        }
        // 求d
        memset(vis, false, (n+1) * sizeof(bool));
        queue<int> Q;
        d[1] = 0; vis[1] = true;
        Q.push(1);
        while(Q.size()) {
            int u = Q.front(); Q.pop();
            c[d[u]].push_back(u);           // 与1距离相同的点放一起
            int len = edges[u].size();
            for(int i=0;i<len;++i) {
                int v = edges[u][i];
                if(vis[v]) continue;
                d[v] = d[u] + 1;
                vis[v] = true;
                Q.push(v);
            }
        }
        // 求结果f
        for(int i=1;i<=n;++i) f[i] = d[i];  // f初值等于d
        for(int l=n-1;l>0;--l) {            // 由远到近遍历每一点
            int num = c[l].size();
            for(int i=0;i<num;++i) {
                int u = c[l][i];
                int len = edges[u].size();
                for(int j=0;j<len;++j) {
                    int v = edges[u][j];
                    if(d[u] < d[v]) f[u] = min(f[u], f[v]);
                    else f[u] = min(f[u], d[v]);
                }
            }
        }
        for(int i=1;i<=n;++i) printf("%d ", f[i]);
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值