最短路的应用

问题 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 多走多少路呢?

输入

第一行一个正整数 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。
保证没有重边。

思路:考虑变化长度的路一定在最短路中,所以先找出最短路,对路上每一条权值*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
",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
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/ztdf123/p/11314096.html