题目描述
每天早晨,FJ 从家中穿过农场走到牛棚。农场由 N N N 块农田组成,农田通过 M M M 条双向道路连接,每条路有一定长度。FJ 的房子在 1 1 1 号田,牛棚在 N N N 号田。没有两块田被多条道路连接,以适当的路径顺序总是能在农场任意一对田间行走。当 FJ 从一块田走到另一块时,总是以总路长最短的道路顺序来走。
FJ 的牛呢,总是不安好心,决定干扰他每天早晨的计划。它们在 M M M 条路的某一条上安放一叠稻草堆,使这条路的长度加倍。牛希望选择一条路干扰使得 FJ 从家到牛棚的路长增加最多。它们请你设计并告诉它们最大增量是多少。
输入格式
第 1 1 1 行:两个整数 N , M N, M N,M。
第 2 2 2 到 M + 1 M+1 M+1 行:第 i + 1 i+1 i+1 行包含三个整数 A i , B i , L i A_i, B_i, L_i Ai,Bi,Li, A i A_i Ai 和 B i B_i Bi 表示道路 i i i 连接的田的编号, L i L_i Li 表示路长。
输出格式
一个整数,表示通过使某条路加倍而得到的最大增量。
输入输出样例 #1
输入 #1
5 7
2 1 5
1 3 1
3 2 8
3 5 7
3 4 3
2 4 7
4 5 2
输出 #1
2
说明/提示
【样例说明】
若使 3 3 3 和 4 4 4 之间的道路长加倍,最短路将由 1 → 3 → 4 → 5 1 \rightarrow 3 \rightarrow 4 \rightarrow 5 1→3→4→5 变为 1 → 3 → 5 1 \rightarrow 3 \rightarrow 5 1→3→5。
【数据规模和约定】
对于 30 % 30\% 30% 的数据, N ≤ 70 N \le 70 N≤70, M ≤ 1 500 M \le 1\,500 M≤1500。
对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 100 1 \le N \le 100 1≤N≤100, 1 ≤ M ≤ 5 000 1 \le M \le 5\,000 1≤M≤5000, 1 ≤ L i ≤ 1 000 000 1 \le L_i \le 1\,000\,000 1≤Li≤1000000。
思路
首先跑一遍最短路,看原最短需要走多少。
接着,枚举在每条边放稻草堆,跑最短路,记录最大增量。
注意:不能直接在 FJ 原来走的最短路中最长的边放,因为他还可以走其他边。
代码
cpp
#include<bits/stdc++.h>
using namespace std;
int g[100001],n,m,dis[100001],to[100001],cnt,head[100001],p,Next[100001],w[100001],maxn=INT_MIN;
bool vis[100001];
queue<int>q;
void add(int u,int v,int l)
{
++cnt;
to[cnt]=v;
Next[cnt]=head[u];
head[u]=cnt;
w[cnt]=l;
}
void spfa()
{
for(int i=1;i<=n;i++)
dis[i]=INT_MAX;
memset(vis,0,sizeof vis);
dis[1]=0;
q.push(1);
vis[1]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=Next[i])
{
int v=to[i];
if(dis[v]>dis[u]+w[i])
{
dis[v]=dis[u]+w[i];
if(!vis[v])
{
q.push(v);
vis[v]=1;
}
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
add(x,y,z);
add(y,x,z);
}
spfa();
int disn=dis[n];
for(int i=1;i<=m;i++)
{
w[i*2-1]*=2;
w[i*2]*=2;
spfa();
maxn=max(maxn,dis[n]-disn);
w[i*2-1]/=2;
w[i*2]/=2;
}
cout<<maxn;
return 0;
}