老年选手,脑洞真心跟不上啊
k个点,可以分为2个集合s1,s2
显然dijkstra一遍即可得到s1到s2的最小距离
考虑枚举2进制的每一位
若第i位=1,则分进s1,否则分进s2
显然所有不同的pair组合都被包含了
#include<stdio.h>
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define MEM(a,x) memset(a,x,sizeof(a))
#define lowbit(x) ((x)&-(x))
using namespace std;
const int inf=1e9+7;
const int N=100000+5;//顶点数
vector<pll>G[N];
vector<int>sel;
ll dis[N];
void Dijkstra(int n,const vector<int>&s){
fill(dis,dis+n+1,1e18);
priority_queue<pll,vector<pll>,greater<pll> >que;
for(int x:s){
dis[x]=0;
que.push({dis[x],x});
}
while(!que.empty()){
int u=que.top().second;
que.pop();
for(const pll&e:G[u]){
ll v=e.first,w=e.second;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
que.push({dis[v],v});
}
}
}
}
vector<int>s,e;
ll slove(int n){
ll ans=1e18;
for(int i=0;i<20;++i){
s.clear();
e.clear();
for(int j:sel){
if((j>>i)&1){
s.push_back(j);
}
else{
e.push_back(j);
}
}
Dijkstra(n,s);
for(int x:e){
ans=min(ans,dis[x]);
}
Dijkstra(n,e);
for(int x:s){
ans=min(ans,dis[x]);
}
}
return ans;
}
int main()
{
//freopen("/home/lu/code/r.txt","r",stdin);
//freopen("/home/lu/code/w.txt","w",stdout);
int T;
scanf("%d",&T);
for(int tt=1;tt<=T;++tt){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
G[i].clear();
}
for(int i=0;i<m;++i){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
G[u].push_back({v,w});
//G[v].push_back({u,w});
}
int k;
scanf("%d",&k);
sel.clear();
while(k--){
int x;
scanf("%d",&x);
sel.push_back(x);
}
printf("Case #%d: %lld\n",tt,slove(n));
}
return 0;
}