计蒜之道 2017 程序设计大赛 - 计蒜客 复赛 D 百度地图导航 最短路、Dijkstra的拓展
2017-06-11 18:49
441 查看
计蒜之道 2017 程序设计大赛 - 计蒜客 复赛 D 百度地图导航
17.79%
1000ms
131072K
百度地图上有 nn 个城市,城市编号依次为 11 到 nn。地图中有若干个城市群,编号依次为 11 到 mm。每个城市群包含一个或多个城市;每个城市可能属于多个城市群,也可能不属于任何城市群。
地图中有两类道路。第一类道路是 城市之间的快速路,两个城市 u,vu,v 之间增加一条距离为 cc 的边;第二类道路是城市群之间的高速路,连接两个城市群 a,ba,b,通过这条高速路,城市群 aa 里的每个城市与城市群 bb 里的每个城市之间两两增加一条距离为 cc 的边。图中所有边均为无向边。
你需要计算从城市 ss 到城市 tt 的最短路。
输入格式
第一行输入 n(1\le n \le 20000),n(1≤n≤20000), m(0
\le m \le 20000)m(0≤m≤20000),分别表示城市总数和城市群总数。
接下来一共输入 mm 行。
第 ii 行首先输入一个 k_i(1
\le k_i \le n)ki(1≤ki≤n),表示第 ii 个城市群中的城市数为 k_iki。接下来输入 k_iki 个数,表示第 ii 个城市群中每个城市的编号(保证一个城市群内的城市编号不重复且合法,\sum_{i=1}^{m}k_i
\le 20000∑i=1mki≤20000)。
下一行输入一个整数 m_1(0
\le m_1 \le 20000)m1(0≤m1≤20000),表示有 m_1m1 条第一类道路,即 城市之间的快速路。
接下来 m_1m1 行,每行输入三个整数 u_i,v_i(1
\le u_i, v_i \le n),c_i(1 \le c_i \le 10^6)ui,vi(1≤ui,vi≤n),ci(1≤ci≤106),分别表示快速路连接的两个城市编号和边的距离。
下一行输入一个整数 m_2(0
\le m_2 \le 20000)m2(0≤m2≤20000),表示有 m_2m2 条第二类道路,即 城市群之间的高速路。
接下来 m_2m2 行,每行输入三个整数 a_i,b_i(1
\le a_i, b_i \le m),l_i(1 \le l_i \le 10^6)ai,bi(1≤ai,bi≤m),li(1≤li≤106),分别表示快速路连接的两个城市群编号和边的距离。
最后一行输入 s,
t(1 \le s, t \le n)s,t(1≤s,t≤n),表示起点和终点城市编号。
输出格式
输出一个整数,表示城市 ss 到城市 tt 到最短路。如果不存在路径,则输出-1。
样例说明
1 -> 2 - > 5或者
1 -> 4 -> 5是最短的路径,总长度为 1212。
样例输入
5 4 2 5 1 2 2 4 1 3 2 3 4 2 1 2 9 1 5 18 2 1 2 6 1 3 10 1 5
样例输出
12
Source
计蒜之道 2017 程序设计大赛 - 计蒜客 复赛 D 百度地图导航计蒜客 15969 百度地图导航
My Solution
题意:有 n 个点,编号依次为 1 到 n,且有若干个点的集合,编号依次为 1 到 m。每个点集合包含一个或多个点;每个点可能属于多个点集合,也可能不属于任何点集合。图中中有两种边。第一类边是点u,v 之间权值为ci的无向边;第二类边是点集合之间的无向边,连接两个点集合 a,b,通过这条边,城市群 a 里的每个点与点集合 b 里的每个点之间有一条权值为 w 的无向边。求从点s 到点 t 的最短路。
最短路、Dijkstra的拓展
这里n+m是4e4所以很可能只能用O(nlogn)的算法,所以可以用Dijkstra+堆优化来进行拓展,
这里把点集合 a作为点 a+n来进行存储,然后dis[i]表示当前从起点s到点或者点集合i的最短路权值。
然后建立这个点集合到点的映射 vector from[a], 和点到它所在的集合的映射 vector to[u]。
然后跑Dijkstra的时候,如果从小根堆取出的点是表示普通的点则和普通的Dijkstra一样跑,
然后对于这个点映射出的点集合也跑一边松弛操作,
szto = to[u].size();
for(j = 0; j < szto; j++){
sz = sons[to[u][j]].size();
uu = to[u][j];
for(i = 0; i < sz; i++){
v = sons[uu][i].first;
w = sons[uu][i].second;
if(d + w < dis[v]){
dis[v] = d + w;
pq.push(ii(dis[v], v));
}
}
}
如果 u>n则表示这是一个点集合,在进行常规松弛操作之后,还要把dis[u]更新到所有的 点集合u映射到的点,
sz = from[u].size();
for(i = 0; i < sz; i++){
v = from[u][i];
if(d < dis[v]){
dis[v] = d;
pq.push(ii(dis[v], v));
}
}
跑完Dijkstra后答案就是dis[destination]了。
时间复杂度 O((n+m)log(n+m))
空间复杂度 O(N)
#include <iostream> #include <cstdio> #include <queue> #include <vector> #include <cstring> using namespace std; typedef long long LL; typedef pair<LL, LL> ii; const int MAXN = 4e4 + 8; const LL INF = 9e18 + 8; vector<int> to[MAXN], from[MAXN]; vector<ii> sons[MAXN]; LL dis[MAXN]; bool vis[MAXN]; priority_queue<ii, vector<ii>, greater<ii> > pq; //O(nlogn) inline void dijkstra(int n, int src) { for(int i = 1; i <= n; i++){ dis[i] = INF; } memset(vis, false, sizeof vis); dis[src] = 0; while(!pq.empty()) pq.pop(); pq.push(ii(0, src)); LL u, v, w, d, sz, i, j, szto, uu; while(!pq.empty()){ u = pq.top().second; d = pq.top().first;//cout << u << " " << d << endl; pq.pop(); if(vis[u]) continue; vis[u] = true; // sz = sons[u].size(); for(i = 0; i < sz; i++){ v = sons[u][i].first; w = sons[u][i].second; if(d + w < dis[v]){ dis[v] = d + w; pq.push(ii(dis[v], v)); } } // szto = to[u].size(); for(j = 0; j < szto; j++){ sz = sons[to[u][j]].size(); uu = to[u][j]; for(i = 0; i < sz; i++){ v = sons[uu][i].first; w = sons[uu][i].second; if(d + w < dis[v]){ dis[v] = d + w; pq.push(ii(dis[v], v)); } } } // sz = from[u].size(); for(i = 0; i < sz; i++){ v = from[u][i]; if(d < dis[v]){ dis[v] = d; pq.push(ii(dis[v], v)); } } } } int main() { #ifdef LOCAL freopen("d.txt", "r", stdin); //freopen("d.txt", "w", stdout); int T = 1; while(T--){ #endif // LOCAL ios::sync_with_stdio(false); cin.tie(0); LL n, m, k, i, j, m1, m2, src, dest, e, u, v, w, ans = INF; cin >> n >> m; for(i = 1; i <= m; i++){ cin >> k; for(j = 0; j < k; j++){ cin >> u; to[u].push_back(i+n); from[i+n].push_back(u); } } cin >> m1; while(m1 && m1--){ cin >> u >> v >> w; sons[u].push_back(ii(v, w)); sons[v].push_back(ii(u, w)); } cin >> m2; while(m2 && m2--){ cin >> u >> v >> w; sons[u+n].push_back(ii(v+n, w)); sons[v+n].push_back(ii(u+n, w)); } cin >> src >> dest; dijkstra(n+m, src); ans = dis[dest]; /* int sz = to[dest].size(), szfrom, uu; for(i = 0; i < sz; i++){ uu = to[dest][i]; szfrom = from[uu].size(); for(j = 0; j < szfrom; j++){ ans = min(ans, dis[from[uu][j]]); } } */ if(ans == INF) cout << -1 << endl; else cout << ans << endl; #ifdef LOCAL cout << endl; } #endif // LOCAL return 0; }
Thank you!
------from ProLights
相关文章推荐
- 计蒜之道 2017 程序设计大赛 - 计蒜客 复赛 B Windows 画图 几何、平面、枚举
- 计蒜之道 2017 程序设计大赛 - 计蒜客 复赛 F 腾讯消消乐 状态压缩dp、枚举+剪枝
- 2017 计蒜之道 复赛 百度地图导航(拆点最短路)
- [最短路] 2017 计蒜之道 复赛 D. 百度地图导航
- 2017 计蒜之道 复赛 百度地图导航 (拆点+最短路)
- 2017 计蒜之道 复赛 百度地图导航【思维+最短路】
- 2017计蒜之道复赛 百度地图导航 (最短路)
- (最短路)2017 计蒜之道 复赛 D. 百度地图导航
- 2017计蒜之道程序设计大赛复赛题解
- 2017计蒜之道程序设计大赛初赛第四场题解
- 2017计蒜之道程序设计大赛初赛第五场
- 2017计蒜之道程序设计大赛初赛第一场题解
- 2017计蒜之道程序设计大赛初赛第六场题解
- 2017 计蒜客复赛 D.百度地图导航
- 2017计蒜之道程序设计大赛初赛第二场题解
- 2017计蒜之道程序设计大赛初赛第五场
- 2017 计蒜之道 百度地图导航(缩点+最短路)
- star.baidu.com程序设计大赛初赛、复赛题目
- 2017计蒜之道程序设计大赛初赛第五场题解
- 2017计蒜之道程序设计大赛初赛第三场题解