1. 程式人生 > >刷題總結———長跑路徑(ssoj1982)

刷題總結———長跑路徑(ssoj1982)

lib pair n) 起點 empty 無向圖 最短 break cstring

題目:

給定一個無向圖···求特定幾個點中兩兩間的最短路中的最小值····其中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; }

刷題總結———長跑路徑(ssoj1982)