题目大意
给定 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<=400,1<=m<=50000,1<=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;
}