• 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;  
    }
    

      

  • 相关阅读:
    chrome/edge 自签名证书造成浏览器无法访问
    linux 下 取进程占用内存(MEM)最高的前10个进程
    总结记录一下我对YZ数据中台指标相关平台的理解感悟与思考
    史上最全之微信群发拼手气红包测试用例
    vue使用filterBy,orderBy实现搜索筛选功能
    前端处理防抖和节流
    箭头函数()=>{}与function的区别
    html不用任何控件上传文件
    Java必备知识--线程池
    Java必备知识--日志框架
  • 原文地址:https://www.cnblogs.com/guangheli/p/13387812.html
Copyright © 2020-2023  润新知