luogu P3008 道路与航线

题目

Farmer John is conducting research for a new milk contract in a new territory. He intends to distribute milk to T (1 <= T <= 25,000) towns conveniently numbered 1…T which are connected by up to R (1 <= R <= 50,000) roads conveniently numbered 1…R and/or P (1 <= P <= 50,000) airplane flights conveniently numbered 1…P.
Either road i or plane i connects town A_i (1 <= A_i <= T) to town B_i (1 <= B_i <= T) with traversal cost C_i. For roads, 0 <= C_i <= 10,000; however, due to the strange finances of the airlines, the cost for planes can be quite negative (-10,000 <= C_i <= 10,000).
Roads are bidirectional and can be traversed from A_i to B_i or B_i to A_i for the same cost; the cost of a road must be non-negative.
Planes, however, can only be used in the direction from A_i to B_i specified in the input. In fact, if there is a plane from A_i to B_i it is guaranteed that there is no way to return from B_i to A_i with any sequence of roads and planes due to recent antiterror regulation.
Farmer John is known around the world as the source of the world’s finest dairy cows. He has in fact received orders for his cows from every single town. He therefore wants to find the cheapest price for delivery to each town from his distribution center in town S (1 <= S <= T) or to know that it is not possible if this is the case.
MEMORY LIMIT: 64MB
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) 把奶牛送到每个城镇的最便宜的方案,或者知道这是不可能的。
输入输出格式
输入格式:
Line 1: Four space separated integers: T, R, P, and S
Lines 2…R+1: Three space separated integers describing a road: A_i, B_i and C_i
Lines R+2…R+P+1: Three space separated integers describing a plane: A_i, B_i and C_i
输出格式:
Lines 1…T: The minimum cost to get from town S to town i, or ‘NO PATH’ if this is not possible
输入输出样例
输入样例#1:
6 3 3 4
1 2 5
3 4 5
5 6 10
3 5 -100
4 6 -100
1 3 -10
输出样例#1:
NO PATH
NO PATH
5
0
-95
-100
说明
6 towns. There are roads between town 1 and town 2, town 3 and town 4, and town 5 and town 6 with costs 5, 5 and 10; there are planes from town 3 to town 5, from town 4 to town 6, and from town 1 to town 3 with costs -100, - 100 and -10. FJ is based in town 4.
FJ’s cows begin at town 4, and can get to town 3 on the road. They can get to towns 5 and 6 using planes from towns 3 and 4. However, there is no way to get to towns 1 and 2, since they cannot go
backwards on the plane from 1 to 3.

题解

  • 求出图中的连通块,记录 i i i所属连通块的编号
  • 统计每个连通块的入度
  • 拓扑排序
  • 对于每一个连通块内作 d i j k s t r a dijkstra dijkstra

code

#include <bits/stdc++.h>
using namespace std;
const int maxm = 2e5 + 100;
const int maxn = 25007;
const int inf = 0x3f3f3f3f;

template <typename T>
inline void read(T &s) {
    s = 0;
    T w = 1, ch = getchar();
    while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
    while (isdigit(ch))  { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
    s *= w;
}

template <typename T>
inline void write(T s) {
    if (s < 0) putchar('-'), s = -s;
    if (s > 9) write(s / 10); 
    putchar(s % 10 + '0');
}

int t, r, p, s, tot, tot2, cnt;
int lin[maxn], lin2[maxn], col[maxn], dis[maxn], in[maxn];
struct Edge { int next, to, dis;  bool opt; } edge[maxm];
struct Edge2 { int next, to; } edge2[maxm];
bool vis[maxn];
vector <int> a[maxn];
priority_queue < pair <int, int> > q;
queue <int> que;

inline void add(int from, int to, int dis, int opt) {
    edge[++tot].to = to;
    edge[tot].opt = opt;
    edge[tot].dis = dis;
    edge[tot].next = lin[from];
    lin[from] = tot;
}

inline void add2(int from, int to) {
    edge2[++tot2].to = to;
    edge2[tot2].next = lin2[from];
    lin2[from] = tot2;
    in[to]++;
}

void dfs(int u) {
    for (int i = lin[u]; i; i = edge[i].next) {
        int v = edge[i].to;
        if (col[v] != 0 && col[v] != col[u]) {
            a[ col[v] ].push_back(v);
            add2(col[u], col[v]);
        }
        if (col[v]) continue;
        if (edge[i].opt) {
            col[v] = ++cnt;
            a[ col[v] ].push_back(v);
            add2(col[u], col[v]);
        }
        else col[v] = col[u];
        dfs(v);
    }
}

void dijkstra(int k) {
    for (int i = 0; i < a[k].size(); ++i) {
        int x = a[k][i];
        q.push( make_pair(-dis[x], x) );
    }
    while (!q.empty()) {
        int dist = q.top().first, u = q.top().second;
        dist = -dist;
        q.pop();
        while (!q.empty() && dist > dis[u]) {
            dist = q.top().first, u = q.top().second;
            dist = -dist;
            q.pop();
        }
        if (q.empty() && dist > dis[u]) break;
        for (int i = lin[u]; i; i = edge[i].next) {
            int v = edge[i].to;
            if (dis[v] > dis[u] + edge[i].dis) {
                dis[v] = dis[u] + edge[i].dis;
                if (col[v] == k) {
                    q.push( make_pair(-dis[v], v) );
                }
            }
        }
    }
}

int main() {
    int x, y, z;
    read(t), read(r), read(p), read(s);
    for (int i = 1; i <= r; ++i) {
        read(x), read(y), read(z);
        add(x, y, z, 0); add(y, x, z, 0);
    }
    for (int i = 1; i <= p; ++i) {
        read(x), read(y), read(z);
        add(x, y, z, 1);
    }

    a[1].push_back(s);
    col[s] = ++cnt;
    dfs(s);
    
    que.push(1);
    memset(dis, 0x3f, sizeof(dis));
    dis[s] = 0;
    for (int i = 1; i <= cnt; ++i) {
        int u = que.front(); que.pop();
        dijkstra(u);
        for (int j = lin2[u]; j; j = edge2[j].next) {
            int v = edge2[j].to;
            in[v]--;
            if (in[v] == 0) que.push(v);
        }
    }
    for (int i = 1; i <= t; ++i) {
        if (!col[i]) puts("NO PATH");
        else printf("%d ", dis[i]), putchar('\n');
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值