Senior Pan
题目链接
题意:有n个点,m条边的有向图,然后从中拿出k个点,然后要我们求出这k个点中距离最短的两个点。
分析:巧妙的用了二进制的思想,对于一个点上的一个二进制位,我们可以知道,不是1就是0,那么我们就可以通过判断这个二进制位是否是1来将这k个点的分成两个集合,由于n的大小只有1e5,所以最多只需要枚举20个二进制为, 然后就是当把k个点分成两个集合后,就是求两个集合之间的最短距离了,求两个集合之间的最短距离就可以用dijkstra来求,其实跟求点到点的最短距离差不多,区别就是一开始先将一个集合的点先放进优先队列,然后当出队的是另一个集合的点,说明最短距离找到了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e5+10;
const long long inf=1e17;
int n,m,k;
int num[maxn];
int mark[maxn],vis[maxn];
ll dis[maxn];
struct Edge{
int to,nex,w;
}edge[maxn];
struct node {
int u;
ll dis;
bool operator <(const node &t)const {
return dis>t.dis;
}
};
priority_queue<node>q;
int tot,head[maxn];
void addedge(int u,int v,int w){
edge[tot]=Edge{v,head[u],w};
head[u]=tot++;
}
void init(){
memset (mark,0,sizeof (mark));
memset (vis,0,sizeof (vis));
for (int i=0;i<=n;i++)dis[i]=inf;
while (!q.empty())q.pop();
}
ll dijkstra(){
while (!q.empty()){
node tmp=q.top();q.pop();
int u=tmp.u;
if (mark[u])return tmp.dis;//如果遇到背标记的一个点,那么就是到达另一个集合的最短距离了
if (vis[u])continue;
vis[u]=true;
for (int i=head[u];i!=-1;i=edge[i].nex){
int v=edge[i].to;
int cost=edge[i].w;
if (!vis[v]&&dis[v]>dis[u]+cost){
dis[v]=dis[u]+cost;
q.push(node{v,dis[v]});
}
}
}
return inf;
}
ll solve(){
ll ans=inf;
for (int i=0;i<20;i++){//通过二进制将k个数的集合分成两个集合,求集合到集合的最短距离
init();
for (int j=0;j<k;j++){
if (num[j]&(1<<i)){
mark[num[j]]=1;
}else {
dis[num[j]]=0;
q.push(node{num[j],0});
}
}
ans=min(ans,dijkstra());
init();
for(int j=0;j<k;j++){//由于是有向图,所以得分两种情况
if (num[j]&(1<<i)){
q.push(node{num[j],0});
}
else {
mark[num[j]]=1;
}
}
ans=min(ans,dijkstra());
}
return ans;
}
int main()
{
int T;
scanf ("%d",&T);
int cas=1;
while (T--){
scanf ("%d%d",&n,&m);
tot=0;
memset (head,-1,sizeof (head));
int u,v,w;
for (int i=0;i<m;i++){
scanf ("%d%d%d",&u,&v,&w);
addedge(u,v,w);
}
scanf ("%d",&k);
for (int i=0;i<k;i++){
scanf ("%d",&num[i]);
}
printf ("Case #%d: %lld\n",cas++,solve());
}
return 0;
}