• bzoj2200道路和航线


    试题描述
    Farmer John 正在一个新的销售区域对他的牛奶销售方案进行调查。他想把牛奶送到 T (1≤T≤2.5×10^4)个城镇 ,编号为 1 到 T。这些城镇之间通过 R 条道路(编号为 1 到 R)和 P 条航线(编号为 1 到 P)连接。每条道路 i 或者航线 i 连接城镇 Ai到 Bi,花费为 Ci。
    对于道路,0≤Ci≤104,然而航线的花费很神奇,花费 Ci可能是负数。道路是双向的,可以从 Ai到 Bi,也可以从 Bi到 Ai,花费都是 Ci。然而航线与之不同,只可以从 Ai到 Bi。
    事实上,由于最近恐怖主义太嚣张,为了社会和谐,出台了一些政策保证:如果有一条航线可以从 Ai到 Bi,那么保证不可能通过一些道路和航线从 Bi回到 Ai。由于 FJ 的奶牛世界公认十分给力,他需要运送奶牛到每一个城镇。他想找到从发送中心城镇 S 把奶牛送到每个城镇的最便宜的方案,或者知道这是不可能的。
    输入
    第一行为四个空格隔开的整数:T,R,P,S;
    第二到第 R+1 行:三个空格隔开的整数(表示一条道路):Ai,Bi和 Ci;
    第 R+2 到 R+P+1行:三个空格隔开的整数(表示一条航线):Ai,Bi和 Ci。
    输出
    输出 T 行,第 i 行表示到达城镇 i 的最小花费,如果不存在输出 NO PATH。
    输入示例
    6 3 3 4 
    1 2 5 
    3 4 5 
    5 6 10 
    3 5 -100 
    4 6 -100 
    1 3 -10
    输出示例
    NO PATH 
    NO PATH 


    -95 
    -100
    其他说明
    样例说明
    一共六个城镇。在 1 和 2,3 和 4,5 和 6 之间有道路,花费分别是 5,5,10。同时有三条航线:3→5,4→6 和 1→3,花费分别是 −100,−100,−10。FJ 的中心城镇在城镇 4。FJ 的奶牛从 4 号城镇开始,可以通过道路到达 3 号城镇。然后他们会通过航线达到 5 和 6 号城镇。但是不可能到达 1 和 2 号城镇。
    数据范围与提示
    对于全部数据,1≤T≤2.5×10^4,1≤R,P≤5×10^4,1≤Ai,Bi,S≤T。保证对于所有道路,0≤Ci≤10^4,对于所有航线,−10^4≤Ci≤10^4。

    听网上dalao说,这道题要用Tarjan缩点、topo排序和dijkstra,但是我用SPFA加了一点优化就过了。

    这个优化是双向队列优化,注意,所有的SPFA都可以用这个优化!

    每当更新完一个节点以后,要将其入队时,如果朴素算法就是将其直接插入队尾。但优化是将其与队首元素进行比较,如果比它更优,那么就将其插入队首。

    双向队列就是deque,其中插入队首是Q.push()_front、队尾是Q.push()_back,然后弹出也是双向的,同理。

    具体看代码:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <cstdlib>
    #include <queue>
    #include <stack>
    #include <vector>
    using namespace std;
    #define MAXN 25010
    #define MAXM 200010
    #define INF 10000009
    #define MOD 10000007
    #define LL long long
    #define in(a) a=read()
    #define REP(i,k,n) for(int i=k;i<=n;i++)
    #define DREP(i,k,n) for(int i=k;i>=n;i--)
    #define cl(a) memset(a,0,sizeof(a))
    inline int read(){
        int x=0,f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
        return x*f;
    }
    inline void out(int x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) out(x/10);
        putchar(x%10+'0');
    }
    int n,m1,m2,s;
    deque <int> Q;
    int dis[MAXN],vis[MAXN],total=0;
    int head[MAXN],to[MAXN*6],nxt[MAXN*6],val[MAXN*6];
    inline void adl(int a,int b,int c){
        total++;
        to[total]=b;
        val[total]=c;
        nxt[total]=head[a];
        head[a]=total;
        return ;
    }
    inline void SPFA(int s){
        memset(dis,127,sizeof(dis));
        dis[s]=0;
        vis[s]=1;
        Q.push_front(s);
        while(!Q.empty()){
            int u=Q.front();
            Q.pop_front();
            vis[u]=0;
            for(int e=head[u];e;e=nxt[e])
                if(dis[to[e]]>dis[u]+val[e]){
                    dis[to[e]]=dis[u]+val[e];
                    if(vis[to[e]])  continue;
                    vis[to[e]]=1;
                    if(!Q.empty())
                        if(dis[to[e]]<dis[Q.front()])  Q.push_front(to[e]);
                        else  Q.push_back(to[e]);
                    else  Q.push_back(to[e]);
                }
        }
        return ;
    }
    int main(){
        in(n);in(m1);in(m2);in(s);
        int a,b,c;
        REP(i,1,m1){
            in(a);in(b);in(c);
            adl(a,b,c);
            adl(b,a,c);
        }
        REP(i,1,m2){
            in(a);in(b);in(c);
            adl(a,b,c);
        }
        SPFA(s);
        REP(i,1,n) 
            if(dis[i]>=INF)  printf("NO PATH
    ");
            else  printf("%d
    ",dis[i]);
        return 0;
    }
  • 相关阅读:
    Win10设置多时区时钟方法技巧
    Win10技巧:使用“照片”应用剪辑视频、添加特效
    kk录像机怎么剪辑视频 kk录像机视频剪辑教程
    360快剪辑怎么使用 360快剪辑软件使用方法介绍
    WPF HyperLink链接下划线隐藏
    ORACLE 如何产生一个随机数
    电脑的开始菜单点不了 用户帐户出现在桌面上
    无法加载DLL"***.dll":找不到指定的模块
    C#调用dll提示"试图加载格式不正确的程序"原因及解决方法
    C#中与C++中的 LPWSTR(wchar_t *) 对应的类型
  • 原文地址:https://www.cnblogs.com/jason2003/p/9621612.html
Copyright © 2020-2023  润新知