题目:
给定一个无向图···求特定几个点中两两间的最短路中的最小值····其中1≤N,M≤100000;T≤5;1≤K≤n;1≤边长≤100000,T为一个测试点的测试数··k为测试点数量
题解:
我们按1到k给每个点编一个编号······然后枚举编号的二进制的每一位,将这一位为1的点连边S(作为起点),为0的点连边T(作为终点),跑最短路就可以了···时间复杂度n*logn*logn···
以后求最短路都用dijkstra不用SPFA了···注意当我们一求出连向T的点中第一个点的最小值时就可以break了····因为每个点每次入队时的距离就是其最小值··
不得不说按二进制分类的方法很妙啊···
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<algorithm> #include<string> #include<queue> using namespace std; priority_queue< pair<int,int> >que; const int N=1e5+5; int first[N],go[N*2],next[N*2],val[N*2],tot; int T,n,m,k,spep[N],num[N],ans,dis[N]; inline int R() { char c;int f=0; for(c=getchar();c<'0'||c>'9';c=getchar()); for(;c<='9'&&c>='0';c=getchar()) f=(f<<3)+(f<<1)+c-'0'; return f; } inline void pre() { memset(first,0,sizeof(first));tot=0;ans=0x3f3f3f3f;memset(num,0,sizeof(num)); } inline void comb(int a,int b,int c) { next[++tot]=first[a],first[a]=tot,go[tot]=b,val[tot]=c; next[++tot]=first[b],first[b]=tot,go[tot]=a,val[tot]=c; } inline void getans() { for(int t=0;(1<<t)<=k;t++) { memset(dis,0x3f3f3f3f,sizeof(dis)); while(!que.empty()) que.pop(); for(int i=1;i<=k;i++) if(num[spep[i]]&(1<<t)) dis[spep[i]]=0,que.push(make_pair(0,spep[i])); while(!que.empty()) { int u=que.top().second; que.pop(); if(num[u]&&!(num[u]&(1<<t))) {ans=min(ans,dis[u]);break;} for(int e=first[u];e;e=next[e]) { int v=go[e]; if(dis[v]>dis[u]+val[e]) { dis[v]=dis[u]+val[e]; que.push(make_pair(-dis[v],v)); } } } } } int main() { //freopen("a.in","r",stdin); T=R(); while(T--) { pre(); n=R(),m=R();int a,b,c; for(int i=1;i<=m;i++) a=R(),b=R(),c=R(),comb(a,b,c); k=R(); for(int i=1;i<=k;i++) spep[i]=R(),num[spep[i]]=i; getans();cout<<ans<<endl; } return 0; }