最短路的应用
问题 F: 路
时间限制: 1 Sec 内存限制: 128 MB提交: 364 解决: 103
[提交] [状态] [命题人:admin]
题目描述
Farmer John 热衷于散步,每天早上他都要从 1 号仓库走到 n 号仓库。 Farmer John 家的 n 个仓库被 m 条双向道路连通起来,每条道路有一个长度 w。而Farmer John 又不喜欢走路,所以他走的是从 1 号仓库到 n 号仓库的最短路。
但是 Farmer 的奶牛们总想搞点事情,他们计划着把 m 条道路的其中一条变成原来长度的 2 倍,使得 Farmer John 可能会多走一点路。
他们想知道,最多能让 Farmer John 多走多少路呢?
但是 Farmer 的奶牛们总想搞点事情,他们计划着把 m 条道路的其中一条变成原来长度的 2 倍,使得 Farmer John 可能会多走一点路。
他们想知道,最多能让 Farmer John 多走多少路呢?
输入
第一行一个正整数 n,m,表示仓库个数和道路条数。
接下来 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。
保证没有重边。
思路:考虑变化长度的路一定在最短路中,所以先找出最短路,对路上每一条权值*2,再跑最短路记录下差值
问题:虽然思路很明确,但是实现的时候疯狂出问题,最后才发现,每次]找出最短路以后,全局变量pre[]数组已经改变,找初始最短路的for循环就会出错,所以在进入dijstra之前先记录一下pre,因为它会改变;
修改方法2:写两个dijstra,一个记录pre,另一个不记录即可
代码如下:
#include <bits/stdc++.h> using namespace std; const int maxn =300; const int inf = 0x3f3f3f3f3f3f3f; struct E { int v,w; friend bool operator< (E x,E y) { return x.w>y.w; } }; vector <E> edge[maxn]; int dis[maxn],vis[maxn],milen; int pre[maxn]; void dijheap(int s,int n) { priority_queue <E> Q; memset(vis,0,sizeof(vis)); memset(pre,0,sizeof(pre)); for (int i=0; i<=n; i++) dis[i]=inf; Q.push({s,0}); dis[s]=0; while(!Q.empty()) { E cur=Q.top();//保证取出的队首元素就是距离s最近的 Q.pop(); int cv=cur.v; if (vis[cv]) continue; vis[cv]=1; int num=edge[cv].size(); for (int i=0;i<num;i++)//用这个点去扩展relax { int v=edge[cv][i].v,w=edge[cv][i].w; if (!vis[v]) { if (dis[v]>dis[cv]+w) { dis[v]=dis[cv]+w; Q.push({v,dis[v]}); pre[v]=cv; } } } } } int findway(int s,int t,int n) { int ret=0; for (int i=t;i!=s;) { for (int j=0;j<edge[pre[i]].size();j++) { if (edge[pre[i]][j].v==i) { //printf("%d %d %d\n",i,pre[i],edge[pre[i]][j].w); edge[pre[i]][j].w*=2; int p=pre[i]; dijheap(1,n); edge[p][j].w/=2; i=p; ret=max(ret,dis[n]-milen); break; } } } return ret; } int main() { int n,m; //freopen("10.in","r",stdin); cin>>n>>m; for (int i=0;i<m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); edge[u].push_back({v,w}); edge[v].push_back({u,w}); } dijheap(1,n); milen=dis[n]; //cout<<milen<<endl; int ans=findway(1,n,n); printf("%d\n",ans); return 0; }