百度地图上有 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
思路:
这类题很套路。
对于两个群,如果我们直接互相建边的话,边数肯定非常多,那么我们肯定解决问题就在于如何减少建边操作。
因为一个群之间的距离不是0.那么我们额外建立出来两个点,将群内所有点连入第一个点,权值为0.然后将另一个点连入群内所有的点,权值也是0.
一个作为群连出的点,一个作为连入的点。
那么对于建边,直接两个城市之间直接建边即可。
两个群之间的点,我们只要连接其额外建立出来的两个点即可。
假设123现在是一个群,45是一个群,两个群之间要建边的话可以直接抽象为这个样子了:
那么接下来建好图之后,直接跑最短路即可。
Ac代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
struct node
{
int from;
int to;
int w;
int next;
}e[2500000];
ll INF=1000000000000000;
int cont;
int vis[60050];
ll dist[60050];
int head[60050];
void add(int from,int to,int w)
{
e[cont].to=to;
e[cont].w=w;
e[cont].next=head[from];
head[from]=cont++;
}
int n,m;
void SPFA()
{
int ss,tt;
scanf("%d%d",&ss,&tt);
queue<int >s;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n*2+m;i++)dist[i]=INF;
dist[ss]=0;
s.push(ss);
while(!s.empty())
{
int u=s.front();
vis[u]=0;
s.pop();
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
if(dist[v]>dist[u]+w)
{
dist[v]=dist[u]+w;
if(vis[v]==0)
{
vis[v]=1;
s.push(v);
}
}
}
}
if(dist[tt]==INF)printf("-1\n");
else
printf("%lld\n",dist[tt]);
}
int main(){
while(~scanf("%d%d",&n,&m))
{
cont=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++)
{
int k;
scanf("%d",&k);
for(int j=0;j<k;j++)
{
int x;
scanf("%d",&x);
add(x,i+n,0);
add(i+2*n,x,0);
}
}
int q;
scanf("%d",&q);
for(int i=0;i<q;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
add(x,y,w);
add(y,x,w);
}
scanf("%d",&q);
for(int i=0;i<q;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
/*
for(int j=0;j<mp[y].size();j++)
{
int v=mp[y][j];
int u=x+n;
add(u,v,w);
}
for(int j=0;j<mp[x].size();j++)
{
int v=mp[x][j];
int u=y+n;
add(u,v,w);
}
*/
add(x+n,y+2*n,w);
add(y+n,x+2*n,w);
}
SPFA();
}
}