【题目】
LOJ
一幅
n
n
n个点
m
m
m条有向带权边的图,给定
k
k
k个关键点,求关键点两两最短路的最小值。
n
≤
1
0
5
,
m
≤
5
×
1
0
5
n\leq 10^5,m\leq 5\times 10^5
n≤105,m≤5×105
【解题思路】
这是个大原题,
HDU6166
\text{HDU6166}
HDU6166。
通过二进制分组将所有关键点分成
S
S
S集和
T
T
T集,跑多源多汇最短路,反过来再做一次即可。当然可以新建超级源和超级汇来做,不过都一样了。
这里的二进制分组是指根据
2
k
2^k
2k位是
0
0
0还是
1
1
1分成两组,显然这样可以遍历所有情况。
复杂度
O
(
n
log
m
log
n
)
O(n\log m\log n)
O(nlogmlogn)
【参考代码】
#include<bits/stdc++.h>
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,int> pii;
const int N=1e5+10,M=5e5+10;
const ll inf=0x3f3f3f3f3f3f3f3f;
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
namespace DreamLolita
{
int n,m,K,tot;
int head[N],a[N],vis[N];
ll ans,dis[N];
struct Tway{int v,w,nex;}e[M];
void add(int u,int v,int w){e[++tot]=(Tway){v,w,head[u]};head[u]=tot;}
priority_queue<pii,vector<pii>,greater<pii> >q;
void dij(int now)
{
memset(dis,0x3f,sizeof(dis));memset(vis,0,sizeof(vis));
for(int i=1;i<=K;++i) if(a[i]&now) {dis[a[i]]=0;q.push(mkp(0,a[i]));}
while(!q.empty())
{
int x=q.top().se;q.pop();
if(vis[x]) continue; vis[x]=1;
for(int i=head[x];i;i=e[i].nex)
{
int v=e[i].v;
if(!vis[v] && dis[x]+e[i].w<dis[v]) dis[v]=dis[x]+e[i].w,q.push(mkp(dis[v],v));
}
}
for(int i=1;i<=K;++i) if(!(a[i]&now)) ans=min(ans,dis[a[i]]);
memset(dis,0x3f,sizeof(dis));memset(vis,0,sizeof(vis));
for(int i=1;i<=K;++i) if(!(a[i]&now)) {dis[a[i]]=0;q.push(mkp(0,a[i]));}
while(!q.empty())
{
int x=q.top().se;q.pop();
if(vis[x]) continue; vis[x]=1;
for(int i=head[x];i;i=e[i].nex)
{
int v=e[i].v;
if(!vis[v] && dis[x]+e[i].w<dis[v]) dis[v]=dis[x]+e[i].w,q.push(mkp(dis[v],v));
}
}
for(int i=1;i<=K;++i) if(a[i]&now) ans=min(ans,dis[a[i]]);
}
void clear(){tot=0;memset(head,0,sizeof(head));}
void solution()
{
n=read();m=read();K=read();
for(int i=1,u,v;i<=m;++i) u=read(),v=read(),add(u,v,read());
for(int i=1;i<=K;++i) a[i]=read();
ans=inf;
for(int i=0;i<17;++i) dij(1<<i);
printf("%lld\n",ans);
clear();
}
}
int main()
{
#ifdef Durant_Lee
freopen("LOJ3087.in","r",stdin);
freopen("LOJ3087.out","w",stdout);
#endif
int T=read();
while(T--) DreamLolita::solution();
return 0;
}