最短路记录路径(模板)

描述:https://www.luogu.com.cn/problem/P2176

每天早晨,FJ从家中穿过农场走到牛棚。农场由 N 块农田组成,农田通过 M 条双向道路连接,每条路有一定长度。FJ 的房子在 1 号田,牛棚在 N 号田。没有两块田被多条道路连接,以适当的路径顺序总是能在农场任意一对田间行走。当FJ从一块田走到另一块时,总是以总路长最短的道路顺序来走。

FJ 的牛呢,总是不安好心,决定干扰他每天早晨的计划。它们在 M 条路的某一条上安放一叠稻草堆,使这条路的长度加倍。牛希望选择一条路干扰使得FJ 从家到牛棚的路长增加最多。它们请你设计并告诉它们最大增量是多少。


很明显的最短路。我们可以选择一条路来加倍边权。

简单,我会暴力枚举(●ˇ∀ˇ●)

那样会超时的

考虑哪些边是不用枚举的。

如果没有把稻草放在最初FJ走的最短路上,那一定是无效的,毕竟FJ只走最短路。

那我们就需要记录最短路的路径,然后枚举最短路经过的边,再跑最短路。

    if(dis[e.to]>dis[ans.num]+e.w){
                pre[e.to]=i;fr[e.to]=ans.num;//节点前驱 

在原来的基础上加了这个。fr数组记录的是目标点的前驱。最后一个目标点是n,那么我们可以一直顺着上去找到1.

pre数组记录的是每个节点松弛时对应的边,毕竟我们要对边操作。

    int now=n,nu=0;
    while(now!=1){
        that[++nu]=pre[now];
        now=fr[now];
    } 

然后我们开始倒序装进that数组。

枚举边进行修改边权时,由于是无向边,所以正反两边都要修改。

比如路径记录的是编号为3的边,那么其实编号4的边也要修改。记录的是4编号3也要修改。

为什么呢?建图的时候就是两条边连着存嘛~

#include<iostream>
#include<cstring>
#include<cstdio>
#define M 15000
#include<queue> 
#define N 110
using namespace std;
int n,m;
int po,ans;
int head[N],to[M],next[M],len[M],e=1;
void buid(int u,int v,int l)
{
    next[++e]=head[u],head[u]=e;
    to[e]=v,len[e]=l;
}
int dis[N],init[N];
int pre[N],fr[N],that[M],nu;
queue<int> q;
void spfa(int s)
{
    memset(dis,20,sizeof(dis));
    dis[s]=0;init[s]=1,q.push(s);
    while(!q.empty())
    {
        int now=q.front();q.pop();init[now]=0;
        for(int i=head[now];i;i=next[i])
        {
            int j=to[i];
            if(dis[j]>dis[now]+len[i])
            {
                dis[j]=dis[now]+len[i];
                pre[j]=i;fr[j]=now;
                if(!init[j])
                {
                    init[j]=1;q.push(j);
                }
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
    {
        int u,v,l;
        scanf("%d%d%d",&u,&v,&l);
        buid(u,v,l);
        buid(v,u,l);
    }
    spfa(1);po=dis[n];
    int now=n;
    while(now!=1)
    {
        that[++nu]=pre[now];//记路径
        now=fr[now];
    }
    for(int i=1;i<=nu;++i)//枚举路径
    {
        len[that[i]]*=2;
        len[that[i]^1]*=2;
        spfa(1);//操♂作
        ans=max(ans,dis[n]);
        len[that[i]]/=2;
        len[that[i]^1]/=2;
    }
    cout<<ans-po<<endl;//end
    return 0;
} 
View Code

猜你喜欢

转载自www.cnblogs.com/iss-ue/p/12524422.html