zoukankan      html  css  js  c++  java
  • Codeforces GYM 100876 J

    Codeforces GYM 100876 J - Buying roads 题解

    才不是因为有了图床来测试一下呢,哼(

    题意

    给你(N)个点,(M)条带权边的无向图,选出(K)条边,使得得到的子图联通并且总代价最小,输出最小总代价和一种方案。

    虽然题目里描述的很冗长,但其实这个图有一些性质:它最初是一条链/一个环,然后再有一些结点直接连到这些在链上/环上的结点。、

    下图就是一个(就是样例):

    image-20201006101016651

    做法

    首先我们可以简单的查看点的度数来找到链/环上的点,和连接它们的边。

    然后我们可以通过对链的头和尾添加一条权值大到足够保证不会选到它的边,把链变成环(样例被更改的样子):

    image-20201006101401687

    我们可以枚举选择的是环上的相连的一条链,选择这些环上的边的同时,也贪心地从小到大选择挂在环上(类似于连接(8)(9))的边。

    这里可以枚举链的起点,在不断扩展这条链的右端点(并强制选取达到的它的边)的同时,维护一个堆,堆里存放的是选择的链上挂的边的权值最大值,每次添加时去查看添加的边的权值是否小于这个最大值,然后更新这个堆即可。

    需要注意有选择整个环而非一部分的链的方案。

    程序

    这里把计算答案和构造方案分开了,实现起来可能比较方便。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    int n,m,K;
    vector<pair<int,int>> g[2005];
    vector<int> hang[2005];
    vector<int> node,edge;
    ll w[2005],ans=1e18;
    
    void get_imp(const int &x,const int &p,const int &head){
        node.emplace_back(x);
        for(pair<int,int> &e:g[x]){
            if(e.first!=p&&g[e.first].size()>1){
                edge.emplace_back(e.second);
                if(e.first!=head)get_imp(e.first,x,head);
                return;
            }
        }
    }
    
    void get_ans_val(){
        priority_queue<int> heap;
        ll cur;
        for(int i=0;i<node.size();i++){
            while(!heap.empty())heap.pop();
            cur=0;
            for(int jj=i;jj<i+K&&jj<i+node.size();jj++){
                int j=jj%node.size();
                for(int k=0;k<hang[node[j]].size();k++){
                    if(heap.size()+jj-i<K){
                        heap.emplace(w[hang[node[j]][k]]);
                        cur+=w[hang[node[j]][k]];
                    }else if(heap.top()>w[hang[node[j]][k]]){
                        cur-=heap.top();
                        heap.pop();
                        cur+=w[hang[node[j]][k]];
                        heap.emplace(w[hang[node[j]][k]]);
                    }else break;
                }
                if(heap.size()+jj-i==K){
                    ans=min(ans,cur);
                    cur-=heap.top();
                    heap.pop();
                }
                cur+=w[edge[j]];
            }
            ans=min(ans,cur);
        }
    }
    
    void construct(set<int> &use){
        priority_queue<pair<int,int>> heap;
        ll cur;
        for(int i=0;i<node.size();i++){
            while(!heap.empty())heap.pop();
            cur=0;
            use.clear();
            for(int jj=i;jj<i+K&&jj<i+node.size();jj++){
                int j=jj%node.size();
                for(int k=0;k<hang[node[j]].size();k++){
                    if(heap.size()+jj-i<K){
                        heap.emplace(w[hang[node[j]][k]],hang[node[j]][k]);
                        use.insert(hang[node[j]][k]);
                        cur+=w[hang[node[j]][k]];
                    }else if(heap.top().first>w[hang[node[j]][k]]){
                        cur-=heap.top().first;
                        use.erase(heap.top().second);
                        heap.pop();
                        cur+=w[hang[node[j]][k]];
                        heap.emplace(w[hang[node[j]][k]],hang[node[j]][k]);
                        use.insert(hang[node[j]][k]);
                    }else break;
                }
                if(heap.size()+jj-i==K){
                    if(cur==ans)return;
                    cur-=heap.top().first;
                    use.erase(heap.top().second);
                    heap.pop();
                }
                cur+=w[edge[j]];
                use.insert(edge[j]);
            }
            if(cur==ans)return;
        }
    }
    
    int main(){
    
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
    
        if(fopen("roads.in","r")){
            freopen("roads.in","r",stdin);
            freopen("roads.out","w",stdout);
        }
    
        cin>>n>>m>>K;
        for(int i=1;i<=m;i++){
            static int u,v,W;
            cin>>u>>v>>W;
            g[u].emplace_back(v,i);
            g[v].emplace_back(u,i);
            w[i]=W;
        }
        for(int i=1;i<=n;i++){
            if(g[i].size()==1)hang[g[i].front().first].emplace_back(g[i].front().second);
            else if(node.empty()){
                int cnt=0;
                for(pair<int,int> &e:g[i])cnt+=g[e.first].size()>1;
                if(cnt==1)get_imp(i,-1,i);
            }
        }
        if(node.empty())for(int i=1;i<=n;i++){
            if(g[i].size()>1){
                get_imp(i,-1,i);
                break;
            }
        }
        if(edge.size()+1==node.size()){
            edge.emplace_back(++m);
            w[m]=1e15;
        }
        for(int i=1;i<=n;i++)sort(hang[i].begin(),hang[i].end(),[](const int &a,const int &b){
            return w[a]<w[b];
        });
        get_ans_val();
        cout<<ans<<'
    ';
        set<int> s;
        construct(s);
        for(const int &x:s)cout<<x<<'
    ';
    
        return 0;
    }
    
  • 相关阅读:
    高精度加法和减法。加法还好,减法花了不少时间。
    整数拆分
    二叉搜索树的中位数
    基本有序数组的排序
    log4j手册
    mysql技巧
    vim配置文件
    regex for python like preg_match of php
    字符串按word反转
    the little redis 阅读笔记
  • 原文地址:https://www.cnblogs.com/BlahDuckling747/p/13772820.html
Copyright © 2011-2022 走看看