题目 2412:
信息学奥赛一本通T1503-道路和航线
时间限制: 2s 内存限制: 192MB 提交: 37 解决: 16
题目描述
原题来自:USACO 2011 Jan. Gold
Farmer John 正在一个新的销售区域对他的牛奶销售方案进行调查。他想把牛奶送到 T 个城镇 ,编号为 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 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 号城镇。
数据范围:
对于全部数据,1≤T≤2.5×104,1≤R,P≤5×104,1≤Ai,Bi,S≤T。保证对于所有道路,0≤Ci≤104,对于所有航线,−104≤Ci≤104 。
思路:
看到题目第一时间想到的就是spfa,想着这个题秒了,结果hh,还是卡了。
然后看到了通过求拓扑图,分联通块使用dijkstra,这还是第一次遇见。。
原来负权也有使用dijkstra的可能性。
88分解(spfa):
#include<bits/stdc++.h> using namespace std; typedef pair<int, int>PII; const int N = 1e5 + 10, M = 2e5 + 10; int h[N], e[M], ne[M], w[M], idx; int dis[N]; bool st[N]; int n, m, k, s; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++; } void spfa() { queue<int>q; memset(dis, 0x3f, sizeof dis); q.push(s); dis[s] = 0; st[s] = true; while (q.size()) { int t = q.front(); q.pop(); st[t] = false; for (int i = h[t];~i;i = ne[i]) { int j = e[i]; if (dis[j] > dis[t] + w[i]) { dis[j] = dis[t] + w[i]; if (st[j]) { continue; } q.push(j); st[j] = true; } } } } void solve() { cin >> n >> m >> k >> s; memset(h, -1, sizeof h); for (int i = 1;i <= m;i++) { int a, b, c; cin >> a >> b >> c; add(a, b, c); add(b, a, c); } for (int i = 1;i <= k;i++) { int a, b, c; cin >> a >> b >> c; add(a, b, c); } spfa(); for (int i = 1;i <= n;i++) { if (dis[i] == 0x3f3f3f3f) { cout << "NO PATH" << endl; } else { cout << dis[i] << endl; } } } int main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); solve(); return 0; }
满分解:
#include<bits/stdc++.h> using namespace std; typedef pair<int, int>PII; const int N = 1e5 + 10, M = 2e5 + 10; int h[N], e[M], ne[M], w[M], idx; int du[N]; int dis[N]; bool st[N]; int cnt[N]; int n, m, k, s; int th; queue<int>q; vector<int>g[N]; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++; } void dfs(int x, int th) { cnt[x] = th; g[th].push_back(x); for (int i = h[x];~i;i = ne[i]) { int j = e[i]; if (cnt[j]) { continue; } dfs(j, th); } } void dij(int v) { priority_queue<PII, vector<PII>, greater<PII>>qq; for (int u : g[v]) { qq.push({ dis[u],u }); } while (qq.size()) { auto t = qq.top(); qq.pop(); int p = t.second; if (st[p]) { continue; } st[p] = true; for (int i = h[p];~i;i = ne[i]) { int j = e[i]; if (cnt[j] != cnt[p] && --du[cnt[j]] == 0) { q.push(cnt[j]); } if (dis[j] > dis[p] + w[i]) { dis[j] = dis[p] + w[i]; if (cnt[j] == cnt[p]) { qq.push({ dis[j],j }); } } } } } void topsort() { memset(dis, 0x3f, sizeof dis); dis[s] = 0; for (int i = 1;i <= th;i++) { if (!du[i]) { q.push(i); } } while (q.size()) { int t = q.front(); q.pop(); dij(t); } } void solve() { cin >> n >> m >> k >> s; memset(h, -1, sizeof h); for (int i = 1;i <= m;i++) { int a, b, c; cin >> a >> b >> c; add(a, b, c); add(b, a, c); } for (int i = 1;i <= n;i++) { if (!cnt[i]) { dfs(i, ++th); } } for (int i = 1;i <= k;i++) { int a, b, c; cin >> a >> b >> c; add(a, b, c); du[cnt[b]]++; } topsort(); for (int i = 1;i <= n;i++) { if (dis[i] > 0x3f3f3f3f/2) { cout << "NO PATH" << endl; } else { cout << dis[i] << endl; } } } int main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); solve(); return 0; }