题目:传送门
题解:城市和城市之间正常建边,将城市群标记成i+n,i+n+m,然后建边方式如下:
设城市群a,b相连和属于a的城市c.
c -> a, a”-> c,b ->a”,a->b”。然后dij一下就可以了。
代码:
#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
using namespace std;
typedef long long int ll;
typedef pair<int,ll>pp;
const int N=1e6+7;
const int mod=1e7+9;
int read(){
int x=0;char ch = getchar();
while('0'>ch||ch>'9')ch=getchar();
while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
}
/********************************************/
int n,m,u,x,v,st,en;
ll c;
int cnt=0;
int head[N];
struct node
{
int to,next;
ll w;
}edge[250000];
void add(int fr,int to,int w)
{
edge[cnt].to=to;
edge[cnt].next=head[fr];
edge[cnt].w=w;
head[fr]=cnt++;
}
struct cmp
{ bool operator ()( pp a,pp b)
{
return a.first>b.first;
}
};
ll dis[N];
int main()
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
memset(dis,-1,sizeof(dis));
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
while(x--)
{
scanf("%d",&u);
add(i+n+m,u,0);
add(u,i+n,0);
}
}
scanf("%d",&x);
for(int i=1;i<=x;i++)
{
scanf("%d%d%lld",&u,&v,&c);
add(u,v,c);
add(v,u,c);
}
scanf("%d",&x);
for(int i=1;i<=x;i++)
{
scanf("%d%d%lld",&u,&v,&c);
add(u+n,v+n+m,c);
add(v+n,u+n+m,c);
}
scanf("%d%d",&st,&en);
dis[st]=0;
priority_queue<pp,vector<pp>,cmp> Q;
Q.push(mp(0,st));
while(!Q.empty()){
int now = Q.top().second;
Q.pop();
for(int i=head[now];i!=-1;i=edge[i].next)
{
int ve=edge[i].to;
ll co=edge[i].w;
if(dis[ve]==-1||dis[now]+co<dis[ve]){
dis[ve]=dis[now]+co;
Q.push(make_pair(dis[ve],ve));
}
}
}
if(dis[en]<0)
printf("-1\n");
else
printf("%lld\n",dis[en]);
return 0;
}