n<=100000个点m<=300000条边有权无向联通图,给出K<=10000个特殊点求K个点中任意两点最短路的最小值。
方法一:K小,随便搞。先构造最短路树,在最短路树上Dijkstra,遇到第一个特殊点就返回。代码如下:
如下个头。首先时间复杂度显然超了,其次建树时要考虑重边,比较难搞。
方法二:多源最短路。
插播:多源最短路方法:把每个源加进初始队列即可。
(1)利用多源最短路求出每个特殊点到其它点的最短路和次短路,利用两个的和来更新。一位大神在比赛中用该方法A过。
(2)直接求每个特殊点到其它点的最短路,把Dijkstra中的vis数组去掉,就是凡是松弛过的点都扔进优先队列里,然后,在松弛前,如果该点已经有最短路了,(我认为)现在访问的这条路径是次短路,直接更新答案。
注意不能用 来自同个特殊点的最短路 更新答案,所以记每个点的最短路来自哪个特殊点。
(3)随机化。把K分成两部分S,T,求S到T的最短路,这样得到正确答案的概率为1/2,多分几次就可以把错误概率降到极低。
代码为方法二(2)。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<queue> 6 //#include<iostream> 7 using namespace std; 8 9 int n,m,K; 10 #define maxn 100011 11 #define maxm 600011 12 const int inf=0x7fffffff; 13 struct Edge{int to,v,next;}; 14 struct Graph 15 { 16 Edge edge[maxm];int le; 17 int first[maxn],dis[maxn],id[maxn],start[maxn];bool vis[maxn]; 18 Graph() 19 { 20 memset(first,0,sizeof(first)); 21 le=2; 22 } 23 void add_edge(int x,int y,int v) 24 { 25 Edge &e=edge[le]; 26 e.to=y;e.v=v; 27 e.next=first[x]; 28 first[x]=le++; 29 } 30 void insert(int x,int y,int v) 31 { 32 add_edge(x,y,v); 33 add_edge(y,x,v); 34 } 35 struct heapnode 36 { 37 int x,v; 38 bool operator < (const heapnode &b) const {return v<b.v;} 39 bool operator > (const heapnode &b) const {return v>b.v;} 40 }; 41 priority_queue<heapnode,vector<heapnode>,greater<heapnode> > q; 42 int ans; 43 int dijkstra() 44 { 45 for (int i=1;i<=n;i++) dis[i]=inf; 46 memset(id,0,sizeof(id)); 47 for (int i=1;i<=K;i++) 48 { 49 dis[start[i]]=0; 50 id[start[i]]=start[i]; 51 q.push((heapnode){start[i],0}); 52 } 53 ans=inf; 54 while (!q.empty()) 55 { 56 const int now=q.top().x,d=q.top().v; 57 q.pop(); 58 if (d!=dis[now]) continue; 59 for (int i=first[now];i;i=edge[i].next) 60 { 61 const Edge &e=edge[i]; 62 if (dis[e.to]!=inf && id[now]!=id[e.to]) 63 ans=min(ans,dis[e.to]+d+e.v); 64 if (dis[e.to]>d+e.v) 65 { 66 dis[e.to]=d+e.v; 67 id[e.to]=id[now]; 68 q.push((heapnode){e.to,dis[e.to]}); 69 } 70 } 71 } 72 return ans; 73 } 74 }G; 75 int x,y,v; 76 int main() 77 { 78 scanf("%d%d%d",&n,&m,&K); 79 for (int i=1;i<=K;i++) scanf("%d",&G.start[i]); 80 for (int i=1;i<=m;i++) 81 { 82 scanf("%d%d%d",&x,&y,&v); 83 G.insert(x,y,v); 84 } 85 printf("%d ",G.dijkstra()); 86 return 0; 87 }