• 道路和航线


    题目描述

    Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查。他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T。这些城镇之间通过R条道路 (1 <= R <= 50,000,编号为1到R) 和P条航线 (1 <= P <= 50,000,编号为1到P) 连接。每条道路i或者航线i连接城镇Ai (1 <= Ai <= T)到Bi (1 <= Bi <= T),花费为Ci。对于道路,0 <= Ci <= 10,000;然而航线的花费很神奇,花费Ci可能是负数(-10,000 <= Ci <= 10,000)。道路是双向的,可以从Ai到Bi,也可以从Bi到Ai,花费都是Ci。然而航线与之不同,只可以从Ai到Bi。事实上,由于最近恐怖主义太嚣张,为了社会和谐,出台 了一些政策保证:如果有一条航线可以从Ai到Bi,那么保证不可能通过一些道路和航线从Bi回到Ai。由于FJ的奶牛世界公认十分给力,他需要运送奶牛到每一个城镇。他想找到从发送中心城镇S(1 <= S <= T) 把奶牛送到每个城镇的最便宜的方案,或者知道这是不可能的。

    输入

    * 第1行:四个空格隔开的整数: T, R, P, and S * 第2到R+1行:三个空格隔开的整数(表示一条道路):Ai, Bi 和 Ci * 第R+2到R+P+1行:三个空格隔开的整数(表示一条航线):Ai, Bi 和 Ci

    输出

    * 第1到T行:从S到达城镇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
    5
    0
    -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号城镇。

     
    正解应该是Tarjan缩点之后,对每一个联通块内部跑dijkstra,联通块之间跑拓扑序,但这样太难写了。
    就写了个优化版的Spfa
    具体操作是用一个双端队列。
    #include <bits/stdc++.h>
    #define  maxn 55055
    using namespace std;
    const int inf =1e9;
    struct Edge
    {
        int v,w,next;
    };
    struct M
    {
        Edge edge[maxn*4];
        int head[maxn];
        int cnt;
        void init()
        {
            memset(head,-1, sizeof(head));
            cnt=0;
        }
        void addedge(int u,int v,int w)
        {
            edge[cnt].v=v;
            edge[cnt].next=head[u];
            edge[cnt].w=w;
            head[u]=cnt++;
        }
    }Mp;
    int dist[maxn];
    bool vis[maxn];
    void Spfa(int s)
    {
        deque<int> q;
        q.push_back(s);
        for(int i=1;i<maxn;i++) dist[i]=inf;
        dist[s]=0;
        while(!q.empty())
        {
            int u=q.front();
            q.pop_front();
            vis[u]=false;
            for(int i=Mp.head[u];i!=-1;i=Mp.edge[i].next)
            {
                int v=Mp.edge[i].v;
                int w=Mp.edge[i].w;
                if(dist[v]>dist[u]+w)
                {
                    dist[v]=dist[u]+w;
                    if(!vis[v])
                    {
                        vis[v]=true;
                        if(!q.empty()&&dist[q.front()]>dist[v]) q.push_front(v);
                        else q.push_back(v);
                    }
                }
            }
        }
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        int n,r,p,s;
        Mp.init();
        scanf("%d%d%d%d",&n,&r,&p,&s);
        for(int i=1;i<=r;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            Mp.addedge(u,v,w);
            Mp.addedge(v,u,w);
        }
        for(int i=1;i<=p;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            Mp.addedge(u,v,w);
        }
        Spfa(s);
        for(int i=1;i<=n;i++)
        {
            if(dist[i]!=inf) printf("%d
    ",dist[i]);
            else printf("NO PATH
    ");
        }
    }
    

      

    每次入队时比较队首与入队元素的距离,如果队首较大,放到队首,否则放到队尾
  • 相关阅读:
    阿里规范
    阿里规范
    阿里规范
    sql 优化步骤
    事务的并发问题:脏读、幻读和不可重复读
    Hive 常见面试题(二)
    yield 的使用
    Java 线程状态
    Lambda 表达式推演全过程
    IDEA 代码自动补全/自动联想 功能
  • 原文地址:https://www.cnblogs.com/zyf3855923/p/9651768.html
Copyright © 2020-2023  润新知