zoukankan      html  css  js  c++  java
  • USACO Roadblock

    洛谷 P2176 [USACO14FEB]路障Roadblock

    洛谷传送门

    JDOJ 2406: USACO 2014 Feb Silver 2.Roadblock

    JDOJ传送门1

    JDOJ 2408: USACO 2014 Feb Gold 1.Roadblock

    JDOJ传送门2

    题目描述

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

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

    输入格式

    第 1 行:两个整数 N, M。

    第 2 到 M+1 行:第 i+1 行包含三个整数 A_i, B_i, L_i,A_i 和 B_i 表示道路 i 连接的田的编号,L_i 表示路长。

    输出格式

    第 1 行:一个整数,表示通过使某条路加倍而得到的最大增量。

    输入输出样例

    输入 #1复制

    输出 #1复制

    说明/提示

    【样例说明】

    若使 3 和 4 之间的道路长加倍,最短路将由 1-3-4-5 变为 1-3-5。

    【数据规模和约定】

    对于 30%的数据,N <= 70,M <= 1,500。

    对于 100%的数据,1 <= N <= 100,1 <= M <= 5,000,1 <= L_i <= 1,000,000。

    备注:

    以上题目描述来自洛谷,数据范围不够JDOJ的,下面附上的代码是JDOJ两道题数据范围的AC代码,当然洛谷也能AC,请大家在看代码的时候不要说我开大了。

    题解:

    最短路的一道好题。

    首先要好好理解一下题目,我一开始以为这就是要求最短路上的一条最长边,后来发现我错了,因为FJ有超能力,他知道奶牛把边一加长,那就不是最短路了,所以他会再选择一条最短路,也就是说,要跑很多遍最短路。

    纠正了这个错误理解,这道题就比较好A了。先记录路径,然后依次枚举把每条边加倍跑最短路,更新最长答案即可。

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int n,m;
    int tot=1,to[50001],val[50001],nxt[50001],head[260];
    int f[260],v[260],ans,temp,now,cnt,pre[260],from[260],path[260];
    void add(int x,int y,int z)
    {
        to[++tot]=y;
        val[tot]=z;
        nxt[tot]=head[x];
        head[x]=tot;
    }
    void spfa()
    {
        memset(f,0x3f,sizeof(f));
        memset(v,0,sizeof(v));
        queue<int> q;
        q.push(1);
        v[1]=1;
        f[1]=0;
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            v[x]=0;
            for(int i=head[x];i;i=nxt[i])
            {
                int y=to[i];
                if(f[y]>f[x]+val[i])
                {
                    f[y]=f[x]+val[i];
                    pre[y]=i;
                    from[y]=x;
                    if(v[y]==0)
                    {
                        q.push(y);
                        v[y]=1;
                    }
                }
            }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        spfa();
        temp=f[n];
        now=n;
        while(now>=1)
        {
            path[++cnt]=pre[now];
            now=from[now];
        }
        for(int i=1;i<=cnt;i++)
        {
            val[path[i]]*=2;
            val[path[i]^1]*=2;
            spfa();
            ans=max(ans,f[n]);
            val[path[i]]/=2;
            val[path[i]^1]/=2;
        }
        printf("%d",ans-temp);
        return 0;
    }
    

    最后提醒大家一些细节。pre数组记录的是边的编号,表示是从哪条边到达的点i,而from数组记录的是点的编号,表示i点的前驱点是哪个点。

    最后最后最后,tot表示边的编号的时候一定要初值置成1,因为我们在跑对偶边的时候用的是^1,如果初值不置成1,会出现极个别情况使得1 ^ 1得0(事实证明的确会WA一个点),而加一之后不影响枚举。

  • 相关阅读:
    多线程与多进程
    网络编程----socketserver多并发实现、FTP上传多并发、udp协议套接字多并发
    网络编程----粘包以及粘包问题的解决、FTP上传
    网络编程----socket介绍、基于tcp协议的套接字实现、基于udp协议的套接字实现
    python基础----软件目录结构规范
    python基础----模块、包
    python基础----异常处理
    python基础----常用模块
    python基础----再看property、描述符(__get__,__set__,__delete__)
    python基础---- __getattribute__----__str__,__repr__,__format__----__doc__----__module__和__class__
  • 原文地址:https://www.cnblogs.com/fusiwei/p/11330474.html
Copyright © 2011-2022 走看看