您的位置:首页 > 其它

计蒜之道 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)k​i​​(1≤k​i​​≤n),表示第 ii 个城市群中的城市数为 k_ik​i​​。接下来输入 k_ik​i​​ 个数,表示第 ii 个城市群中每个城市的编号(保证一个城市群内的城市编号不重复且合法,\sum_{i=1}^{m}k_i
\le 20000∑​i=1​m​​k​i​​≤20000)。

下一行输入一个整数 m_1(0
\le m_1 \le 20000)m​1​​(0≤m​1​​≤20000),表示有 m_1m​1​​ 条第一类道路,即 城市之间的快速路。

接下来 m_1m​1​​ 行,每行输入三个整数 u_i,v_i(1
\le u_i, v_i \le n),c_i(1 \le c_i \le 10^6)u​i​​,v​i​​(1≤u​i​​,v​i​​≤n),c​i​​(1≤c​i​​≤10​6​​),分别表示快速路连接的两个城市编号和边的距离。

下一行输入一个整数 m_2(0
\le m_2 \le 20000)m​2​​(0≤m​2​​≤20000),表示有 m_2m​2​​ 条第二类道路,即 城市群之间的高速路。

接下来 m_2m​2​​ 行,每行输入三个整数 a_i,b_i(1
\le a_i, b_i \le m),l_i(1 \le l_i \le 10^6)a​i​​,b​i​​(1≤a​i​​,b​i​​≤m),l​i​​(1≤l​i​​≤10​6​​),分别表示快速路连接的两个城市群编号和边的距离。

最后一行输入 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: