3445: [Usaco2014 Feb] Roadblock
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 123 Solved: 91
[ Submit][ Status][ Discuss]
Description
有一个无向图,共N个节点,编号1至N,共M条边。FJ在节点1,它想到达节点N。FJ总是会选择最短路径到达节点N。作为捣蛋的奶牛Bessie,它想尽量延迟FJ到达节点N的时间,于是Bessie决定从M条边之中选择某一条边,使得改边的长度变成原来的两倍,由于智商的问题,Bessie不知道选择加倍哪条边的长度才能使得FJ到达N号节点的时间最迟。注意:不管Bessie选择加倍哪条边的长度,FJ总是会从1号节点开始走最短路径到达N号点。
Input
第一行,两个整数N和M. 1 <=N<=250, 1<=M<=250000。
接下来有M行,每行三个整数:A,B,L,表示节点A和节点B之间有一条长度为L的无向边。1<=L<=1000000。
Output
一个整数。Bessie选择了加倍某一条边的长度后,奶牛FJ从节点1到达节点N的最短路径是多少。但是输出的格式有变化,假设Bessie没有加倍某一条边的长度之前,FJ从1号节点到达N号节点的最短路径是X;在Bessie加倍某一条边的长度之后,FJ从1号节点到达N号节点的最短路径是Y,那么你输出的结果是Y-X。
Sample Input
2 1 5
1 3 1
3 2 8
3 5 7
3 4 3
2 4 7
4 5 2
INPUT DETAILS: There are 5 fields and 7 pathways. Currently, the shortest path from the house (field 1) to the barn (field 5) is 1-3-4-5 of total length 1+3+2=6.
Sample Output
(把节点3到节点4的边从原来的长度3变成长度6)
HINT
Source
题解:堆优化dijkstra
一遍扫出最短路,并记录下路径。只有路径上的点发生变化才会影响最短路,然后之间枚举路径上的边,然后计算出此时的最短路,更新答案即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define N 300
#define M 500003
#define LL long long
#define pa pair<LL,int>
using namespace std;
int n,a[N],tot,c[N],cnt,vis[M],m;
int pre[M],next[M],v[M],point[N];
LL dis[N],len[M];
void add(int x,int y,LL z)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; len[tot]=z;
tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; len[tot]=z;
}
void dijkstra()
{
priority_queue<pa,vector<pa>,greater<pa> > p;
memset(dis,127/3,sizeof(dis));
dis[1]=0; p.push(make_pair(dis[1],1));
while (!p.empty()){
int now=p.top().second; p.pop();
for (int i=point[now];i!=-1;i=next[i])
{
LL t=0;
if (vis[i]) t=len[i]*2LL;
else t=len[i];
if (dis[v[i]]>dis[now]+t){
dis[v[i]]=dis[now]+t; pre[v[i]]=i;
p.push(make_pair(dis[v[i]],v[i]));
}
}
}
}
void solve()
{
int now=n;
while (now!=1) {
c[++cnt]=pre[now];
now=v[pre[now]^1];
}
}
int main()
{
freopen("rblock.in","r",stdin);
freopen("rblock.out","w",stdout);
scanf("%d%d",&n,&m);
tot=-1;
memset(point,-1,sizeof(point));
for (int i=1;i<=m;i++){
int x,y; LL z; scanf("%d%d%I64d",&x,&y,&z);
add(x,y,z);
}
dijkstra(); LL ans=dis[n]; LL maxn=0;
solve();
for (int i=1;i<=cnt;i++) {
vis[c[i]]=1; vis[c[i]^1]=1;
dijkstra(); maxn=max(maxn,dis[n]-ans);
vis[c[i]]=0; vis[c[i]^1]=0;
}
printf("%I64d\n",maxn);
}