bzoj 3445: [Usaco2014 Feb] Roadblock (堆优化dijkstra)

3445: [Usaco2014 Feb] Roadblock

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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

5 7
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

2
(把节点3到节点4的边从原来的长度3变成长度6)

HINT

Source

[ Submit][ Status][ Discuss]

题解:堆优化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);
}




  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值