Roadblock

本文介绍了一种解决给定无向图中,通过调整边权后最短路径最大增量问题的策略。通过预处理最短路径并遍历可能的边权倍增操作,利用SPFA算法实时更新最短路径,找到最小增量。适用于n≤400, m≤50000的图结构。
摘要由CSDN通过智能技术生成

题目大意

给定 n n n 个点和 m m m 条边的无向图,任意选择一条边,将这条边的权值乘 2 2 2,问你,从 1 1 1 n n n 的最短路径最大增量是多少。

无重边。

对于 100 % 100\% 100% 的数据, 1 < = n < = 400 , 1 < = m < = 50000 , 1 < = L i < = 1000000 1 <= n <= 400,1 <= m <= 50000,1 <= L_i <= 1000000 1<=n<=4001<=m<=500001<=Li<=1000000

解题思路

比较暴力的 std。。。

首先明确,如果不选择最短路径上的边,那么最短路根本没用变化,不行。

那么先跑一遍 spfa 求出最短路径上的边,记录下来。

枚举每一条刚记录的边,将他的边权乘 2 2 2,在跑一遍 spfa,求出增量。

最后输出最小增量即可。

AC CODE

#include <bits/stdc++.h>

#define int long long

int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-')
            f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}

void write(int x)
{
    if (x < 0)
    {
        putchar('-');
        write(-x);
        return;
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}

using namespace std;

const int _ = 700000 + 10;

int n, m;

int tot = 1, head[_];

struct node
{
    int v, w, nxt;
} e[_ << 1];

struct edg
{
    int i, dis;
    bool operator<(const edg tmp) const
    {
        return tmp.dis < dis;
    }
};

int dis[5005];

int vis[5005];

int ans;

int pre[_], fr[_], t[_], cnt;

void add(int x, int y, int w)
{
    e[++tot].nxt = head[x];
    e[tot].v = y;
    e[tot].w = w;
    head[x] = tot;
}

void spfa(int st)
{
    queue<int> q;
    for (int i = 1; i <= n + 100; ++i)
        dis[i] = INT_MAX;
    dis[st] = 0;
    q.push(st);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i = head[u]; i; i = e[i].nxt)
        {
            int v = e[i].v;
            if (dis[v] > dis[u] + e[i].w)
            {
                dis[v] = dis[u] + e[i].w;
                pre[v] = i;
                fr[v] = u;
                if (!vis[v])
                {
                    q.push(v);
                    vis[v] = 1;
                }
            }
        }
    }
}

signed main()
{
    n = read(), m = read();
    for (int i = 1; i <= m; i++)
    {
        int u, v, dis;
        u = read(), v = read(), dis = read();
        add(u, v, dis);
        add(v, u, dis);
    }
    spfa(1);
    int now = n;
    while (now != 1)
    {
        t[++cnt] = pre[now];
        now = fr[now];
    }
    int ll = dis[n];
    for (int i = 1; i <= cnt; ++i)
    {
        int x = t[i];
        e[x].w *= 2;
        e[x ^ 1].w *= 2;
        spfa(1);
        ans = max(ans, dis[n]);
        e[x].w /= 2;
        e[x ^ 1].w /= 2;
    }
    printf("%lld\n", ans - ll);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值