zoukankan      html  css  js  c++  java
  • LOJ#3087. 「GXOI / GZOI2019」旅行者 二进制分组+Dijkstra

    通过这道题了解二进制分组.      

    由于我们只需要求两两之间最短路的值而不需要求具体是哪两个点得到的最短路,可以使用二进制分组.   

    因为如果两个点对答案有贡献,那么这两个点一定在某个二进制位上不同,而 dijkstra 可以方便地求两个集合之间的最短路.        

    然后注意对于两个方向要分别跑一个 dijkstra.   

    总时间复杂度为 $O( (n+m) log (n+m) log n)$.   

    code: 

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>   
    #define N 100006   
    #define M 500009  
    #define ll long long 
    #define pb push_back   
    #define setIO(s) freopen(s".in","r",stdin)  
    using namespace std;   
    const ll inf=1000000000000000;   
    int n,m,K,s,t,tot;   
    int A[N];  
    struct Edge {
        int v,c;   
        Edge(int v=0,int c=0):v(v),c(c){}   
    };   
    vector<Edge>G[N]; 
    struct Dijkstra {    
        ll d[N];  
        int vis[N];  
        struct data {   
            int u;ll d; 
            data(int u=0,ll d=0):u(u),d(d){}   
            bool operator<(const data b) const {
                return d>b.d;                              
            }
        };  
        priority_queue<data>q;  
        ll solve() {
            for(int i=0;i<=n+1;++i) {
                vis[i]=0,d[i]=inf;  
            }
            d[s]=0;   
            q.push(data(s,0));  
            while(!q.empty()) {
                data e=q.top(); q.pop();   
                int u=e.u;  
                if(vis[u]) {
                    continue;      
                }
                vis[u]=1;    
                for(int i=0;i<G[u].size();++i) {
                    Edge p=G[u][i];  
                    if(d[p.v]>d[u]+1ll*p.c) {
                        d[p.v]=d[u]+1ll*p.c;    
                        q.push(data(p.v,d[p.v]));   
                    }
                }
            }
            return d[t];  
        }
    }D;  
    void solve() {
        int x,y,z;  
        scanf("%d%d%d",&n,&m,&K);    
        for(int i=1;i<=m;++i) {
            scanf("%d%d%d",&x,&y,&z);    
            if(x==y) {
                continue;  
            }
            G[x].pb(Edge(y,z));           
        }
        for(int i=1;i<=K;++i) scanf("%d",&A[i]); 
        s=0,t=n+1;    
        ll ans=inf;  
        for(int i=0;(1<<i)<=n;++i) {
            for(int j=1;j<=K;++j) {
                if((1<<i)&A[j]) {
                    G[s].pb(Edge(A[j],0));  
                }
                else {
                    G[A[j]].pb(Edge(t,0));   
                }
            }
            ans=min(ans,D.solve());  
            for(int j=1;j<=K;++j) {
                if((1<<i)&A[j]) {
                    G[s].pop_back();  
                }
                else {
                    G[A[j]].pop_back();   
                }
            }   
        }
        for(int i=0;(1<<i)<=n;++i) {
            for(int j=1;j<=K;++j) {
                if((1<<i)&A[j]) {
                    G[A[j]].pb(Edge(t,0));  
                }
                else {
                    G[s].pb(Edge(A[j],0));   
                }
            }
            ans=min(ans,D.solve());  
            for(int j=1;j<=K;++j) {
                if((1<<i)&A[j]) {
                    G[A[j]].pop_back();   
                }
                else {
                    G[s].pop_back();
                }
            }   
        }
        printf("%lld
    ",ans);   
        for(int i=0;i<=n+1;++i) {
            G[i].clear();  
        }
    }
    int main() {
        // setIO("input");       
        int T;  
        scanf("%d",&T);   
        while(T--) {
            solve();   
        }
        return 0;  
    }
    

      

  • 相关阅读:
    【杂谈】SpringBoot为啥不用配置启动类
    【API知识】SpringBoot项目中@EnableXXX的原理
    【杂谈】再看生产-消费模式
    【杂谈】Hash表与平衡树
    【杂谈】如何对Redis进行原子操作
    【杂谈】从底层看锁的实现2
    【杂谈】从底层看锁的实现
    HashMap的简易解读
    定时任务、反射、注解
    值得收藏的js原型详解
  • 原文地址:https://www.cnblogs.com/guangheli/p/13387812.html
Copyright © 2011-2022 走看看