zoukankan      html  css  js  c++  java
  • POJ

    题意:一张带权无向图中,有K条边可以免费修建。现在要修建一条从点1到点N的路,费用是除掉免费的K条边外,权值最大的那条边的值,求最小花费。

    分析:假设存在一个临界值X,小于X的边全部免费,那么此时由大于等于X的边组成的图,从点1到点N走过的边数小于等于K,那么这个X就是所求的答案。所以可以通过二分答案的方法求解该问题,每一次根据mid值跑迪杰斯特拉,d[i]记录路径长度(走过边的数目)。需要注意的是,要特判一下点1到点N本身不连通的情况以及花费为0的情况。二分的时候,当d[N]>K时修改答案为mid,因为此时能确定最后的结果一定大于等于mid。

    #include<iostream>
    #include<stdio.h>
    #include<cstring>
    #include<queue>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef int LL;
    const int maxn =1e3+5;
    const int maxm =5e4+5;
    const LL INF =0x3f3f3f3f;
    struct Edge{
        int from,to,next;
        LL val;
        bool operator <(const Edge &e) const {return val<e.val;}
    };
    
    struct HeapNode{
        LL d;           //费用或路径
        int u;
        bool operator < (const HeapNode & rhs) const{return d > rhs.d;}  
    };
    struct Dijstra{
        int n,m,tot;
        Edge edges[maxm];
        bool used[maxn];
        LL d[maxn];
        int head[maxn];
    
        void init(int n){
            this->n = n;
            this->tot=0;
            memset(head,-1,sizeof(head));
        }
    
        void Addedge(int u,int v ,LL dist){
            edges[tot].to = v;
            edges[tot].val = dist;
            edges[tot].next = head[u];
            head[u] = tot++;
        }
    
        int dijkstra(int s,int limit){   
            memset(used,0,sizeof(used));
            priority_queue<HeapNode> Q;
            for(int i=0;i<=n;++i)    d[i]=INF;          //d[i]记录的是到i点走过的权值超过limit的边数
            d[s]=0;
            Q.push((HeapNode){0,s});
            while(!Q.empty()){
                HeapNode x =Q.top();Q.pop();
                int u =x.u;
                if(d[u]<x.d) continue;                      //没有更新的必要,不加判断也对,但是慢一点点
                for(int i=head[u];~i;i=edges[i].next){
                    int nd = d[u]+(edges[i].val>=limit?1:0);
                    int v = edges[i].to;
                    if (d[v] > nd){
                        d[v] = nd;
                        Q.push({d[v], v});
                    }
                }
            }
            return d[n];                  
        }
    }G;
    
    #define LOCAL
    int main()
    {
        #ifdef LOCAL
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
        #endif
        int N,M,K,u,v,k;
        LL tmp;
        while(scanf("%d%d%d",&N,&M,&K)==3){
            G.init(N);
            int maxL = -1;
            for(int i=0;i<M;++i){
                scanf("%d%d%d",&u,&v,&tmp);
                G.Addedge(u,v,tmp);
                G.Addedge(v,u,tmp);
                if(maxL<tmp) maxL = tmp;
            }
            int res = G.dijkstra(1,0);
            if(res==INF){
                printf("-1
    ");
                continue;
            }
            else if(res<=K){                //先特判一下
                printf("0
    ");
                continue;
            }
            int L =0,R=maxL,mid,ans;
            while(L<R){
                mid  =(L+R)>>1;
                if(G.dijkstra(1,mid)>K){    
                    ans = mid;              //此时能确定的是:肯定要花费mid的代价
                    L = mid+1;
                }
                else R =mid-1;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    为了更好的明天
  • 相关阅读:
    [环境]Java 环境变量
    [BZOJ 4008][HNOI2015]亚瑟王(期望Dp)
    [BZOJ 3295][Cqoi2011]动态逆序对(CDQ分治)
    [BZOJ 3668&UOJ #2][Noi2014]起床困难综合症(贪心)
    [BZOJ 4571][Scoi2016]美味(主席树)
    [BZOJ 4408][Fjoi 2016]神秘数(主席树+思路)
    [BZOJ 2212][Poi2011]Tree Rotations(线段树合并)
    [BZOJ 4592][Shoi2015]脑洞治疗仪(线段树)
    [BZOJ 2054]疯狂的馒头(并查集)
    [BZOJ 1455]罗马游戏(左偏树+并查集)
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9348600.html
Copyright © 2011-2022 走看看