蓝桥杯练习题-《道路和航路》解题报告
来源:互联网 发布:js时间滑动选择插件 编辑:程序博客网 时间:2024/05/22 14:13
蓝桥杯练习题-《道路和航路》解题报告
题目链接:http://lx.lanqiao.org/problem.page?gpid=T22
题目描述如下:
农夫约翰正在针对一个新区域的牛奶配送合同进行研究。他打算分发牛奶到T个城镇(标号为1..T),这些城镇通过R条标号为(1..R)的道路和P条标号为(1..P)的航路相连。每一条公路i或者航路i表示成连接城镇Ai(1<=A_i<=T)和Bi(1<=Bi<=T)代价为Ci。每一条公路,Ci的范围为0<=Ci<=10,000;由于奇怪的运营策略,每一条航路的Ci可能为负的,也就是-10,000<=Ci<=10,000。
每一条公路都是双向的,正向和反向的花费是一样的,都是非负的。
每一条航路都根据输入的Ai和Bi进行从Ai->Bi的单向通行。实际上,如果现在有一条航路是从Ai到Bi的话,那么意味着肯定没有通行方案从Bi回到Ai。
农夫约翰想把他那优良的牛奶从配送中心送到各个城镇,当然希望代价越小越好,你可以帮助他嘛?配送中心位于城镇S中(1<=S<=T)。
输入格式
输入的第一行包含四个用空格隔开的整数T,R,P,S。
接下来R行,描述公路信息,每行包含三个整数,分别表示Ai,Bi和Ci。
接下来P行,描述航路信息,每行包含三个整数,分别表示Ai,Bi和Ci。
输出格式
输出T行,分别表示从城镇S到每个城市的最小花费,如果到不了的话输出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
数据规模与约定
对于20%的数据,T<=100,R<=500,P<=500;
对于30%的数据,R<=1000,R<=10000,P<=3000;
对于100%的数据,1<=T<=25000,1<=R<=50000,1<=P<=50000。
这个题目是一个含有负边的最短路问题,可以用SPFA过掉90%的数据,有2组数据过不了,大概是出题人针对SPFA而出的数据。
大概是我实力不济,经过各种尝试没能卡过。于是决定改用dijkstra.
一般来说dijkstra是没法处理含有负权值的图的,但是这题给的图比较特殊。
所有的负权值只可能在航路,也就是单向边中,而所有的单向边都不在环中。
那么整个图就可以看做一个个用公路,也就是双向边连成的块,块与块之间由一些单向边连起来。
强连通缩点之后则变成一个有向无环图……
有向无环图的最短路可以DP出来……
于是想法就有了,首先用并查集维护所有公路连成的块,然后从起点的块开始,在块的内部用dijkstra来求最短路。
块与块之间用类似拓扑排序的方式,维护一个块的入度。当所有指向那个块的单向边的另一端的最短路都已经确定了,才开始在这个块中求最短路。
代码如下:
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#include <stack>#include <vector>#define clr(a,b) memset(a, b, sizeof(a))using namespace std;const int N = 25050;const int E = 150500;//邻接表int h[N], v[E], w[E], nxt[E], el;void initEdge() { clr(h, -1); el = 0;}void addEdge(int x, int y, int z) { v[el] = y; w[el] = z; nxt[el] = h[x]; h[x] = el++;}//并查集int rt[N], ra[N];int Find(int x) { if(x != rt[x]) rt[x] = Find(rt[x]); return rt[x];}void Union(int r1, int r2) { int x = Find(r1), y = Find(r2); if(x == y) return; if(ra[x] > ra[y]) rt[y] = x; else { rt[x] = y; if(ra[x] == ra[y]) ++ra[y]; }}void Init(int n) { for(int i=0; i<=n; i++) ra[i] = 0, rt[i] = i;}struct EDGE { int u, v, w; bool flag; EDGE(){} EDGE(int x, int y, int z, bool f):u(x), v(y), w(z), flag(f){}} edge[E];int edgel;bool visitable[N];void dfs(int x) { visitable[x] = true; for(int i=h[x]; ~i; i=nxt[i]) { if(!visitable[v[i]]) { dfs(v[i]); } }}int indegree[N];bool vis[N];//链表int lh[N], lel, lv[E], lnxt[E];void initLink() { clr(lh, -1); lel = 0;}void addLink(int x, int y) { lv[lel] = y; lnxt[lel] = lh[x]; lh[x] = lel++;}int dis[N];bool tag[N];int main() { int n, r, p, s; scanf("%d%d%d%d", &n, &r, &p, &s); Init(n); initEdge(); edgel = 0; int x, y, z; for(int i=0; i<r; i++) { scanf("%d%d%d", &x, &y, &z); addEdge(x, y, z); addEdge(y, x, z); edge[edgel++] = EDGE(x, y, z, false); Union(x, y); } for(int i=0; i<p; i++) { scanf("%d%d%d", &x, &y, &z); addEdge(x, y, z); edge[edgel++] = EDGE(x, y, z, true); } dfs(s); initEdge(); initLink(); for(int i=0; i<edgel; i++) { if(visitable[edge[i].u] && visitable[edge[i].v]) { addEdge(edge[i].u, edge[i].v, edge[i].w); if(edge[i].flag) { ++ indegree[Find(edge[i].v)]; addLink(Find(edge[i].v), edge[i].v); } else { addEdge(edge[i].v, edge[i].u, edge[i].w); } } } stack<int> zeroDegree; priority_queue<pair<int,int> > que; clr(dis, 0x3f); dis[s] = 0; que.push(make_pair(0, s)); while(!que.empty() || !zeroDegree.empty()) { if(que.empty()) { int x = zeroDegree.top(); zeroDegree.pop(); for(int i=lh[x]; ~i; i=lnxt[i]) { int y = lv[i]; if(!vis[y]) { vis[y] = true; que.push(make_pair(-dis[y], y)); } } } else { int x = que.top().second; que.pop(); if(tag[x]) continue; tag[x] = true; for(int i=h[x]; ~i; i=nxt[i]) { int y = v[i]; if(!tag[y] && dis[y] > dis[x] + w[i]) { dis[y] = dis[x] + w[i]; if(Find(x) == Find(y)) { que.push(make_pair(-dis[y], y)); } } if(Find(x) != Find(y)) { -- indegree[Find(y)]; if(indegree[Find(y)] == 0) { zeroDegree.push(Find(y)); } } } } } for(int i=1; i<=n; i++) { if(visitable[i]) { printf("%d\n", dis[i]); } else { puts("NO PATH"); } } return 0;}
0 0
- 蓝桥杯练习题-《道路和航路》解题报告
- 蓝桥杯 道路和航路
- 蓝桥杯 道路和航路
- 蓝桥杯 - 道路和航路(SPFA)
- 道路和航路
- 道路和航路
- 道路和航路
- 道路和航路
- 道路和航路
- 算法提高 道路和航路
- 道路和航路 Java实现
- 算法提高 道路和航路
- 蓝桥杯 最短路 道路和航路 SPFA算法
- 蓝桥杯 道路和航路(SPFA算法求最短路径)
- 海贼王之伟大航路解题报告
- 蓝桥 算法提高 道路和航路
- 道路覆盖--解题报告
- 蓝桥杯算法训练之道路和航路 (邻接表SPFA+SLF优化)
- 自己搭建远程服务器成功,可以远程访问哦
- linux下的网络程序0——服务器端返回客户端输入
- petsc 结构化数据使用
- 【C#小知识】C#中一些易混淆概念总结(二)--------构造函数,this关键字,部分类,枚举
- [leet code] Valid Sudoku
- 蓝桥杯练习题-《道路和航路》解题报告
- [完全背包]HDOJ 1248寒冰王座
- one-to-one外键双向关联之建表
- hdu 2243 ac自动机+矩阵快速幂
- [VB.NET] 多語言文字加密器
- 【C#小知识】C#中一些易混淆概念总结(二)
- Sum It Up
- 设计模式-工厂模式(二)
- 杭电3724