zoukankan      html  css  js  c++  java
  • 最短路记录路径(模板)

    描述: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
  • 相关阅读:
    poj 2763 Housewife Wind
    hdu 3966 Aragorn's Story
    poj 1655 Balancing Act 求树的重心
    有上下界的网络流问题
    URAL 1277 Cops and Thieves 最小割 无向图点带权点连通度
    ZOJ 2532 Internship 网络流求关键边
    ZOJ 2760 How Many Shortest Path 最大流+floyd求最短路
    SGU 438 The Glorious Karlutka River =) 拆点+动态流+最大流
    怎么样仿写已知网址的网页?
    5-10 公路村村通 (30分)
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12524422.html
Copyright © 2011-2022 走看看