zoukankan      html  css  js  c++  java
  • 题解:[GXOI/GZOI2019]旅行者

    调这个题调了两个月,被自己蠢哭

    题意:

       给一个有向图,一组关键点,求关键点之间的最短的距离

    Solution:

      这个题目有两种做法,分别是 $nlogn$ 和 $nlog^2n$ 的

      首先说 $nlogn$ 的官方做法,我们考虑多源迪杰斯特拉

    正图上从 k 个关键点出发跑 $dijkstra$ ,记某个点离最近的关键点距离为 $dis[0][i]$

    反图上也从 k 个关键点出发跑 $dijkstra$ ,距离记为 $dis[1][i]$

    枚举正图中的边 $u->v: w$, 用 $dis[0][u]+dis[1][v]+w$ 更新答案

      然后就是一种很好打的 $nlognlogk$ 的做法,我们考虑一种思想,二进制分组

    对于每一个在集合中的元素,我们进行重新标号,然后对每一位进行$0/1$二进制分组,由于每个元素的编号不一样,所以至少有一位的分组不同,然后一组连 $S$,一组连 $T$,这样跑 $logk$ 组的从 $S$ 到 $T$ 的最短路,去 $min$,即可

    #include <bits/stdc++.h>
    using namespace std;
    
    #define re register
    #define ll long long
    #define gc getchar()
    inline int read()
    {
     	re int x(0),f(1);re char c(gc);
        while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc;
        while(c>='0'&&c<='9')x=x*10+c-48,c=gc;
        return f*x;
    }
    
    const int N=5e5+10,M=1e6+10;
    ll INF=1e15+7;
    int h[N],n,m,cnt,k,a[N],x[N],y[N],z[N],s,t;
    struct node {int next,to,w;}e[M<<1]; 
    ll dis[N],ans=INF;
    void add(int u,int v,int w){e[++cnt]=(node){h[u],v,w},h[u]=cnt;}
    #define QXX(u) for(int i=h[u],v;v=e[i].to,i;i=e[i].next) 
    
    struct Node 
    {
        int id;ll d;
        bool operator < (const Node a) const {return d>a.d;}
    };
    priority_queue<Node>q;
    
    void dijkstra()
    {
        while(!q.empty()) q.pop();
        for(int i=1;i<=t;++i)
            dis[i]=INF;
        dis[s]=0;
        Node a;
        int u,d;
        q.push((Node){s,0});
        while(!q.empty())
        {
            a=q.top(),q.pop();
            u=a.id,d=a.d;
            if(d!=dis[u]) continue;
            QXX(u)
                if(dis[u]+e[i].w<dis[v])
                {
                    dis[v]=dis[u]+e[i].w;
                    q.push((Node){v,dis[v]});
                }
        }
    } 
    
    void work()
    {
        ans=INF;
        n=read(),m=read(),k=read();
        s=n+1,t=n+2;
        for(int i=1;i<=m;++i)
            x[i]=read(),y[i]=read(),z[i]=read();
        for(int i=1;i<=k;++i)
            a[i]=read();
        for(int q=0;(1<<q)<=k;++q)
        {
            memset(h,0,sizeof(h));
            cnt=0;
            for(int i=1;i<=k;++i)
            {
                if(i&(1<<q)) add(s,a[i],0);
                else add(a[i],t,0); 
            }
            for(int i=1;i<=m;++i)
                add(x[i],y[i],z[i]);
            dijkstra();
            ans=min(ans,dis[t]);
            memset(h,0,sizeof(h));
            cnt=0;
            for(int i=1;i<=k;++i)
            {
                if(i&(1<<q)) add(s,a[i],0);
                else add(a[i],t,0); 
            }
            for(int i=1;i<=m;++i)
                add(y[i],x[i],z[i]);
            dijkstra();
            ans=min(ans,dis[t]);
        }
        cout<<ans<<endl;
    }
    
    int main()
    {
        int T=read();
        while(T--) work();
        return 0;
    } 
    

      

  • 相关阅读:
    从上往下打印二叉树
    栈的压入、弹出序列
    连续子数组的最大和
    链表中环形的入口
    1月项目痛点
    problem:vue组件局部刷新,在组件销毁(destroyed)时取消刷新无效问题
    重点:浏览器的工作原理
    12月中旬项目中出现的几个bug解决方法的思考
    12月中项目问题复盘之对项目进度把控的反思
    problem: vue之数组元素中的数组类型值数据改变却无法在子组件视图更新问题
  • 原文地址:https://www.cnblogs.com/zijinjun/p/11137356.html
Copyright © 2011-2022 走看看