题意:
给定一张
n
n
n个点,
m
m
m条有向边的图,标记其中
k
k
k个点,求这
k
k
k个点之间的两两最短路的最小值
范围&性质:
1
≤
k
,
n
≤
1
0
5
,
1
≤
m
≤
5
×
1
0
5
1\le k, n\le 10^5,1\le m\le 5\times 10^5
1≤k,n≤105,1≤m≤5×105
分析:
暴力
暴力将关键点分成
A
,
B
A,B
A,B两个集合,超级源向
A
A
A集合每一个点连一条边权为0的边,
B
B
B集合每一个点向超级汇连一条边权为
0
0
0的边,然后从超级源向超级汇跑最短路
正解
我们发现暴力枚举的复杂度不太对,然后我们考虑优化,我们发现正解对应的
s
t
,
e
d
st,ed
st,ed他们的编号必定存在一位不一样,那么我们就枚举二进制位,将这位按照0和1划分成两个集合跑最短路,复杂度
O
(
n
l
o
g
n
2
)
O(nlog^2_n)
O(nlogn2)
代码:
#include<bits/stdc++.h>
#define mk(x,y) make_pair(x,y)
using namespace std
;
namespace zzc
{
const int maxn
= 1e5+5;
const int maxm
= 5e5+5;
int head
[maxn
],key
[maxn
],ghead
[maxn
];
long long dis
[maxn
];
int n
,cnt
=0,t
,st
,ed
,gcnt
,m
,k
;
bool vis
[maxn
];
struct edge
{
int to
,nxt
,val
;
}e
[maxm
+maxn
];
void add(int u
,int v
,int w
)
{
e
[++cnt
].to
=v
;
e
[cnt
].val
=w
;
e
[cnt
].nxt
=head
[u
];
head
[u
]=cnt
;
}
void addedge(int u
,int v
,int w
)
{
e
[++gcnt
].to
=v
;
e
[gcnt
].val
=w
;
e
[gcnt
].nxt
=ghead
[u
];
ghead
[u
]=gcnt
;
}
long long dijkstra()
{
memset(dis
,0x3f,sizeof(dis
));
memset(vis
,false,sizeof(vis
));
dis
[st
]=0;
priority_queue
<pair
<long long,int> > q
;
q
.push(mk(0,st
));
while(!q
.empty())
{
int u
=q
.top().second
;q
.pop();
if(vis
[u
]) continue;
vis
[u
]=true;
for(int i
=ghead
[u
];i
;i
=e
[i
].nxt
)
{
int v
=e
[i
].to
;
if(dis
[v
]>dis
[u
]+e
[i
].val
)
{
dis
[v
]=dis
[u
]+e
[i
].val
;
q
.push(mk(-dis
[v
],v
));
}
}
}
return dis
[ed
];
}
void work()
{
int a
,b
,c
;
scanf("%d",&t
);
while(t
--)
{
cnt
=0;
memset(head
,0,sizeof(head
));
scanf("%d%d%d",&n
,&m
,&k
);
for(int i
=1;i
<=m
;i
++)
{
scanf("%d%d%d",&a
,&b
,&c
);
add(a
,b
,c
);
}
for(int i
=1;i
<=k
;i
++) scanf("%d",&key
[i
]);
long long ans
=LLONG_MAX
;
st
=n
+1;ed
=n
+2;
for(int i
=0;(1<<i
)<=n
;i
++)
{
memcpy(ghead
,head
,sizeof(head
));
gcnt
=cnt
;
for(int j
=1;j
<=k
;j
++)
{
if(j
&(1<<i
))
{
addedge(st
,key
[j
],0);
}
else
{
addedge(key
[j
],ed
,0);
}
}
ans
=min(ans
,dijkstra());
memcpy(ghead
,head
,sizeof(head
));
gcnt
=cnt
;
for(int j
=1;j
<=k
;j
++)
{
if(j
&(1<<i
))
{
addedge(key
[j
],ed
,0);
}
else
{
addedge(st
,key
[j
],0);
}
}
ans
=min(ans
,dijkstra());
}
printf("%lld\n",ans
);
}
}
}
int main()
{
zzc
::work();
return 0;
}