百度地图上有 n 个城市,城市编号依次为 1 到 n。地图中有若干个城市群,编号依次为 1 到 m。每个城市群包含一个或多个城市;每个城市可能属于多个城市群,也可能不属于任何城市群。
地图中有两类道路。第一类道路是 城市之间的快速路,两个城市 u,v 之间增加一条距离为 c 的边;第二类道路是城市群之间的高速路,连接两个城市群 a,b,通过这条高速路,城市群 a 里的每个城市与城市群 b 里的每个城市之间两两增加一条距离为 c 的边。图中所有边均为无向边。
你需要计算从城市 s 到城市 t 的最短路。
输入格式
第一行输入 n(1≤n≤20000), m(0≤m≤20000),分别表示城市总数和城市群总数。
接下来一共输入 m 行。
第 i 行首先输入一个 ki(1≤ki≤n),表示第 i 个城市群中的城市数为 ki。接下来输入 ki 个数,表示第 i 个城市群中每个城市的编号(保证一个城市群内的城市编号不重复且合法,∑i=1mki≤20000)。
下一行输入一个整数 m1(0≤m1≤20000),表示有 m1 条第一类道路,即 城市之间的快速路。
接下来 m1 行,每行输入三个整数 ui,vi(1≤ui,vi≤n),ci(1≤ci≤106),分别表示快速路连接的两个城市编号和边的距离。
下一行输入一个整数 m2(0≤m2≤20000),表示有 m2 条第二类道路,即 城市群之间的高速路。
接下来 m2 行,每行输入三个整数 ai,bi(1≤ai,bi≤m),li(1≤li≤106),分别表示快速路连接的两个城市群编号和边的距离。
最后一行输入 s,t(1≤s,t≤n),表示起点和终点城市编号。
输出格式
输出一个整数,表示城市 s 到城市 t 到最短路。如果不存在路径,则输出-1
。
样例说明
1 -> 2 - > 5
或者1 -> 4 -> 5
是最短的路径,总长度为 12。
样例输入
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
思路:最短路之建图难点。其实跟HDU 4725(题解)很像。但是我智障还是错了15次,菜。
建图,有两种方式,一种是拆点,一种是不拆点,这题不拆点会RE。具体做法如下:为每个群增加两个点,一个作为
入点,一个作为出点,在读入第i群包含哪些点的时候建边即可(不拆点得存下来,所以就RE了),即建点x到群i入点
的权为0的单向边,群i出点到点x的权为0的单向边。再在读群之间的关联时,建群a入点到群b出点的单向边,群b入
点到群a出点的单向边。然后跑一个SPFA即可。
Code:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const LL inf = 0x3f3f3f3f3f3f3f3f;
const int maxn = 20005;
const int maxm = 1e6+5;
struct node
{
int v, next;
LL w;
}edge[maxm];
queue<int> q;
int n, m, k, x, m1, m2, no;
int head[maxn*3], vis[maxn*3];
LL dis[maxn*3], c;
void init()
{
no = 0;
memset(head, -1, sizeof head);
memset(dis, 0x3f3f, sizeof dis);
}
inline void add(int u, int v, int w)
{
edge[no].v = v;
edge[no].w = w;
edge[no].next = head[u];
head[u] = no++;
}
void SPFA(int s, int t)
{
while(!q.empty()) q.pop();
memset(vis, 0, sizeof vis);
q.push(s); vis[s] = 1; dis[s] = 0;
while(!q.empty())
{
int tp = q.front(); q.pop();
vis[tp] = 0;
int k = head[tp];
while(k != -1)
{
if(dis[edge[k].v] > dis[tp]+edge[k].w)
{
dis[edge[k].v] = dis[tp]+edge[k].w;
if(vis[edge[k].v] == 0)
{
vis[edge[k].v] = 1;
q.push(edge[k].v);
}
}
k = edge[k].next;
}
}
if(dis[t] == inf) printf("-1\n");
else printf("%lld\n", dis[t]);
}
int main()
{
int a, b;
scanf("%d %d", &n, &m); init();
for(int i = 1; i <= m; ++i)
{
scanf("%d", &k);
for(int j = 1; j <= k; ++j)
{
scanf("%d", &x);
add(x, n+2*i-1, 0);
add(n+2*i, x, 0);
}
}
scanf("%d", &m1);
for(int i = 1; i <= m1; ++i)
{
scanf("%d %d %lld", &a, &b, &c);
add(a, b, c); add(b, a, c);
}
scanf("%d", &m2);
for(int i = 1; i <= m2; ++i)
{
scanf("%d %d %lld", &a, &b, &c);
add(n+a*2-1, n+b*2, c);
add(n+b*2-1, n+a*2, c);
}
scanf("%d %d", &a, &b);
SPFA(a, b);
return 0;
}
继续加油~