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;
}