码迷,mamicode.com
首页 > 其他好文 > 详细

道路与航线

时间:2020-04-30 19:20:22      阅读:82      评论:0      收藏:0      [点我收藏+]

标签:and   long   lse   while   eof   for   memset   mem   算法   

Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查。他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T。这些城镇之间通过R条道路 (1 <= R <= 50,000,编号为1到R) 和P条航线 (1 <= P <= 50,000,编号为1到P) 连接。每条道路i或者航线i连接城镇A_i (1 <= A_i <= T)到B_i (1 <= B_i <= T),花费为C_i。对于道路,0 <= C_i <= 10,000;然而航线的花费很神奇,花费C_i可能是负数(-10,000 <= C_i <= 10,000)。道路是双向的,可以从A_i到B_i,也可以从B_i到A_i,花费都是C_i。然而航线与之不同,只可以从A_i到B_i。事实上,由于最近恐怖主义太嚣张,为了社会和谐,出台 了一些政策保证:如果有一条航线可以从A_i到B_i,那么保证不可能通过一些道路和航线从B_i回到A_i。由于FJ的奶牛世界公认十分给力,他需要运送奶牛到每一个城镇。他想找到从发送中心城镇S(1 <= S <= T) 把奶牛送到每个城镇的最便宜的方案,或者知道这是不可能的。Input* 第1行:四个空格隔开的整数: T, R, P, and S * 第2到R+1行:三个空格隔开的整数(表示一条道路):A_i, B_i 和 C_i * 第R+2到R+P+1行:三个空格隔开的整数(表示一条航线):A_i, B_i 和 C_iOutput* 第1到T行:从S到达城镇i的最小花费,如果不存在输出"NO PATH"。Sample Input 6 3 3 4 1 2 5 3 4 5 5 6 10 3 5 -100 4 6 -100 1 3 -10 样例输入解释: 一共六个城镇。在1-2,3-4,5-6之间有道路,花费分别是5,5,10。同时有三条航线:3->5, 4->6和1->3,花费分别是-100,-100,-10。FJ的中心城镇在城镇4。 Sample Output NO PATH NO PATH 5 0 -95 -100 样例输出解释: FJ的奶牛从4号城镇开始,可以通过道路到达3号城镇。然后他们会通过航线达到5和6号城镇。 但是不可能到达1和2号城镇。

 ————————————————————————————————————————————————

————————————————————————————————————————————————————

下面四思路:

这道题有两种做法:

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

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

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

双向队列就是deque,其中插入队首是Q.push()_front、队尾是Q.push()_back,然后弹出也是双向的,同理。
大家如果不理解可以看代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <iostream>
#define ll long long
using namespace std;
const int maxn=25005,maxm=150005;
const int Inf=0x3f3f3f3f;
int e[maxm],Need[maxm],h[maxm];
int w[maxm],acnt,dis[maxn];
int n,u,p,s;bool now[maxn];
void add(int a,int b,int c){
    e[acnt]=b,Need[acnt]=h[a],w[acnt]=c,h[a]=acnt++;
}
void SPFA(int root){
    deque<int> q;
    memset(dis,0x3f,sizeof dis);
    dis[root]=0;q.push_back(root);now[root]=1;
    while(!q.empty()){
        int res=q.front();q.pop_front();now[res]=0;
        for(int i=h[res];i!=-1;i=Need[i]){
            int v=e[i];
            if(dis[v]>dis[res]+w[i]){
                dis[v]=dis[res]+w[i];
                if(!now[v]){
                    now[v]=1;
                    if(dis[v]>dis[q.front()])q.push_back(v);
                    else q.push_front(v);
                }
            }
        }
    }
}
int main(){
    //freopen("a.in","u",stdin);
    memset(h,-1,sizeof h);
    scanf("%d%d%d%d",&n,&u,&p,&s);
    for(int i=0;i<u;++i){int a,b,c;scanf("%d%d%d",&a,&b,&c);add(a,b,c),add(b,a,c);}
    for(int i=0;i<p;++i){int a,b,c;scanf("%d%d%d",&a,&b,&c);add(a,b,c);}
    SPFA(s);
    for(int i=1;i<=n;++i){
        if(dis[i]>=Inf)printf("NO PATH\n");
        else printf("%d\n",dis[i]);
    }
    return 0;
}

OK

 

道路与航线

标签:and   long   lse   while   eof   for   memset   mem   算法   

原文地址:https://www.cnblogs.com/DZN2004/p/12810526.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!