刷題總結———長跑路徑(ssoj1982)
阿新 • • 發佈:2017-10-16
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)