洛谷P5304 [GXOI/GZOI2019] 旅行者

时间:2019-10-31
本文章向大家介绍洛谷P5304 [GXOI/GZOI2019] 旅行者,主要包括洛谷P5304 [GXOI/GZOI2019] 旅行者使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题意:给定一个n个点,m条边的有向图,有k个被标记的点,求这k个点中任意两个点之间的最短路径的最小值。

n<=100,000 m<=500,000

暴力的思路:对于每个被标记的点都跑一遍dij,然后在其它被标记的点中取min,复杂度 O(k*(n+m)logn)

对于暴力的优化:我们可以对这k个标记点进行二进制分组,分为两组,每次从set1向set2跑最短路取min,

再从set2向set1跑一遍最短路取min,因为若存在两个点之间的最短路为最小值,这两个点的下标的二进制

位一定有一位不一样,从而不被分在同一个组里,正确性被证明,这样只需要跑logk次即可。

复杂度 O(logk*(n+m)logn);

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxn 100010
#define INF 2147483647

using namespace std;

struct node
{
    int ed,len,nxt;
};
node edge[maxn*5];
int n,m,k,first[maxn],cnt,dis[maxn];
int love[maxn];
int set1_cnt,set2_cnt;
int set1[maxn],set2[maxn];
bool vis[maxn];

inline void add_edge(int s,int e,int d)
{
    cnt++;
    edge[cnt].ed=e;
    edge[cnt].len=d;
    edge[cnt].nxt=first[s];
    first[s]=cnt;
    return;
}

inline void dijkstra()
{
    priority_queue < pair <int,int> > heap;
    for(register int i=1;i<=n;++i)
        dis[i]=INF,vis[i]=false;
    for(register int i=1;i<=set1_cnt;++i)
    {
        dis[set1[i]]=0;
        heap.push(make_pair(-dis[set1[i]],set1[i]));
    }
    while(!heap.empty())
    {
        int p=heap.top().second; heap.pop();
        if(vis[p]) continue;
        vis[p]=true;
        for(register int i=first[p];i;i=edge[i].nxt)
        {
            int e=edge[i].ed;
            int d=edge[i].len;
            int newd=dis[p]+d;
            if(newd<dis[e])
            {
                dis[e]=newd;
                heap.push(make_pair(-dis[e],e));
            }
        }    
    }
    return;
}

inline void dijkstra_2()
{
        priority_queue < pair <int,int> > heap;
    for(register int i=1;i<=n;++i)
        dis[i]=INF,vis[i]=false;
    for(register int i=1;i<=set2_cnt;++i)
    {
        dis[set2[i]]=0;
        heap.push(make_pair(-dis[set2[i]],set2[i]));
    }
    while(!heap.empty())
    {
        int p=heap.top().second; heap.pop();
        if(vis[p]) continue;
        vis[p]=true;
        for(register int i=first[p];i;i=edge[i].nxt)
        {
            int e=edge[i].ed;
            int d=edge[i].len;
            int newd=dis[p]+d;
            if(newd<dis[e])
            {
                dis[e]=newd;
                heap.push(make_pair(-dis[e],e));
            }
        }    
    }
    return;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(edge,0,sizeof(edge));
        memset(first,0,sizeof(first));
        cnt=0;
        scanf("%d%d%d",&n,&m,&k);
        for(register int i=1;i<=m;++i)
        {
            int s,e,d;
            scanf("%d%d%d",&s,&e,&d);
            add_edge(s,e,d);
        }
        int ans=2147483647;
        for(register int i=1;i<=k;++i)
            scanf("%d",&love[i]);
        for(register int i=0;(1<<i)<=k;++i)
        {
            set1_cnt=0;
            set2_cnt=0;
            for(register int j=1;j<=k;++j)
            {
                if(((j>>i)&1)==0) set1[++set1_cnt]=love[j];
                else set2[++set2_cnt]=love[j];
            }
            dijkstra();
            for(register int j=1;j<=set2_cnt;++j)
                ans=min(ans,dis[set2[j]]);
            dijkstra_2();
            for(register int j=1;j<=set1_cnt;++j)
                ans=min(ans,dis[set1[j]]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Hoyoak/p/11774033.html