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\n");
        else  printf("%d\n",dis[i]);
    return 0;
}

 

posted @ 2018-09-10 18:20  Dijkstra·Liu  阅读(721)  评论(0编辑  收藏  举报