• 最短路记录路径(模板)


    描述: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
  • 相关阅读:
    Eclipse中配置约束(DTD,XSD)
    Eclipse集成tomcat
    java使用dom4j对XML进行CURD操作
    SQL数据库操作(CURD)
    Java-IO流总结
    Java-集合框架总结
    AES apache commons-crypto 对称加密
    Redis
    Axis2 客户端调用 设置超时时间
    Sybase 修改数据库默认排序
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12524422.html
Copyright © 2020-2023  润新知