类比cf 835E,枚举二进制位按照标号当前位为1 和当前位为0分为两个集合,每次求解两个集合之间的最短路即可覆盖到所有的点对。时间复杂度20*dijstla时间
G++ AC c++会超时。
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
typedef long long ll;
const ll inf = 0x3f3f3f3f3f3f3f3fLL;
const int maxn = 100010;
int n;
struct node
{
int to;
int next;
ll w;
node(){}
node(int a,int b,ll c):to(a),next(b),w(c){}
}edge[maxn<<1];
struct Edge
{
int id;
ll dist;
Edge(int a, ll b):id(a),dist(b){}
bool operator < (const Edge& T)const{
return dist>T.dist;
}
};
ll dist[maxn],z[maxn];
int tot;
int head[maxn];
int x[maxn],y[maxn],c[maxn];
void add_edge(int u,int v,ll w)
{
edge[tot] = node(v,head[u],w);
head[u] = tot++;
}
priority_queue<Edge>q;
long long dij()
{
for(int i=0;i<=n+1;i++) dist[i]=inf;
dist[0] = 0;
q.push(Edge(0,0));
while(!q.empty())
{
Edge fr = q.top(); q.pop();
int u = fr.id;
if(dist[u]<fr.dist) continue;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v = edge[i].to;
if(dist[v]>dist[u] + edge[i].w)
{
dist[v] = dist[u] + edge[i].w;
//printf("%lld\n",dist[v]);
q.push(Edge(v,dist[v]));
}
}
}
//printf("%I64d\n",dist[n+1]);
return dist[n+1];
}
int main()
{
int cases,t=1,m,k;
scanf("%d",&cases);
while(cases--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
scanf("%d%d%I64d",&x[i],&y[i],&z[i]);
scanf("%d",&k);
for(int i=0;i<k;i++) scanf("%d",&c[i]);
ll ans = inf;
for(int r=0;r<20;r++)
{
tot = 0; memset(head,-1,sizeof(head));
for(int i=0;i<m;i++) add_edge(x[i],y[i],z[i]);
for(int i=0;i<k;i++)
{
if(c[i]&(1<<r)) add_edge(0,c[i],0);
else add_edge(c[i],n+1,0);
}
ans = min(ans,dij());
tot = 0; memset(head,-1,sizeof(head));
for(int i=0;i<m;i++) add_edge(x[i],y[i],z[i]);
for(int i=0;i<k;i++)
{
if((c[i]&(1<<r))==0) add_edge(0,c[i],0);
else add_edge(c[i],n+1,0);
}
ans = min(ans,dij());
}
printf("Case #%d: ",t++);
printf("%I64d\n",ans);
}
return 0;
}