时间限制: 1 Sec 内存限制: 128 MB
题目描述
Farmer John 热衷于散步,每天早上他都要从 1 号仓库走到 n 号仓库。 Farmer John 家的 n 个仓库被 m 条双向道路连通起来,每条道路有一个长度 w。而Farmer John 又不喜欢走路,所以他走的是从 1 号仓库到 n 号仓库的最短路。
但是 Farmer 的奶牛们总想搞点事情,他们计划着把 m 条道路的其中一条变成原来长度的 2 倍,使得 Farmer John 可能会多走一点路。
他们想知道,最多能让 Farmer John 多走多少路呢?
输入
第一行一个正整数 n,m,表示仓库个数和道路条数。
接下来 m 行,每行三个正整数,表示每条双向道路的连接的仓库和该双向道路的长度。
输出
输出只有一行,表示最多能让 Farmer John 每天早上多走多少路。
样例输入
复制样例数据
5 7
2 1 5
1 3 1
3 2 8
3 5 7
3 4 3
2 4 7
4 5 2
样例输出
2
提示
一开始的最短路为1→3→4→5,长度为1+3+2=6。
将连接3和4的边变为原来的两倍,3×2=6。
改造后的图,最短路为1→3→5,长度为1+7=8。
多走了8−6=2的路程,可以证明这是最大的答案。
对于50%的数据,1≤n≤50。
对于100%的数据,1≤n≤250,1≤m≤25000,1≤w≤106。
保证没有重边。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=300;
const int INF=0x3f3f3f3f;
bool vis[maxn];
ll d[maxn];
int way[maxn][maxn];
int path[maxn];
int n,m,u,v,w;
bool once=true;
void Dijkstra()
{
memset(vis,false,sizeof(vis));
d[1]=0;
for(int i=2;i<=n;i++)
d[i]=INF;
for(int i=1;i<=n;i++)
{
int x,m=INF;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&d[j]<=m)
{
m=d[j];
x=j;
}
}
vis[x]=true;
for(int y=1;y<=n;y++)
{
if(way[x][y]==0)continue;
if(d[y]>d[x]+way[x][y])
{
d[y]=d[x]+way[x][y];
if(once)
{
path[y]=x;
}
}
}
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=0;i<m;i++)
{
scanf("%d %d %d",&u,&v,&w);
way[u][v]=w;
way[v][u]=w;
}
Dijkstra();
ll minway=d[n];
once=false;
int pos=n;
ll maxminway=minway;
while(true)
{
way[pos][path[pos]]<<=1;
way[path[pos]][pos]<<=1;
Dijkstra();
if(d[n]>maxminway)maxminway=d[n];
way[pos][path[pos]]>>=1;
way[path[pos]][pos]>>=1;
if(pos==1)break;
else pos=path[pos];
}
printf("%lld\n",maxminway-minway);
return 0;
}