刷题总结———长跑路径(ssoj1982)

题目:

  给定一个无向图···求特定几个点中两两间的最短路中的最小值····其中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;
}

 

posted @ 2017-10-16 14:15  AseanA  阅读(166)  评论(0编辑  收藏  举报