zoukankan      html  css  js  c++  java
  • whu 1471 All Your Bases 暴力删边

    题意:

      N个顶点(N<=10000),N-1条边,每条边含有一个权值,有T个基地,需要删除K条边,形成K+1个连通块,使每个连通块包含至少一个基地.

      求最小花费.

    解法:

      还是太弱. 看完题没敢想 O(N^2)的算法,最初想建模求最小割,后面又想到点分治,但是O(N^2)的空间复杂度。。。。。

      其实题目给了10S, 将所有边从小到大排序后, 尝试删除该边,若此边两端 联通快,都包含基地,则删除. 处理出来K+1个联通块就是答案了.

    View Code
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N = (int)1e4+10;
    
    struct Edge{
        int a,b,c;
        void input(){
            scanf("%d%d%d",&a,&b,&c);    
        }
        bool operator <(const Edge tmp) const{
            return c < tmp.c;    
        }
    }edge[N];
    int n, t, k, sum;
    bool used[N], milit[N];
    int st[N], r[N];
    int st1[N], r1[N];
    int find1(int x){
        return x == st[x] ? x : (st[x]=find1(st[x]));
    }
    int find2(int x){
        return x == st1[x] ? x : (st1[x]=find2(st1[x]));
    }
    void init(){
        for(int i = 1; i <= n; i++){
            st1[i] = i, r1[i] = (milit[i] ? 1 : 0); 
        }     
        for(int i = 0; i < n-1; i++){
            if( used[i] ){ 
                int x = find2( edge[i].a ), y = find2( edge[i].b );
                if( x != y )
                    st1[x] =  y, r1[y] |= r1[x];      
            }    
        }
    }
    int solve(){
        for(int i = 1; i <= n; i++)
            st[i] = i, r[i] = (milit[i] ? 1 : 0);  
        int t_sum = 0, num = 0;
        for(int i = 0; i < n-1; i++){ 
            int x = find1( edge[i].a ), y = find1( edge[i].b ); 
            st[x] =  y; r[y] |= r[x];    
            t_sum += edge[i].c;
            used[i] = true;  
        }  
        for(int i = 1; i <= n; i++){
            if( i == st[i] ) num++;    
        }
        if( num < (k+1) ){ 
            for(int i = 0; i < n-1; i++){
                int a = edge[i].a, b = edge[i].b;
                if( num == (k+1) ) break;
                if( used[i] ){    
                    used[i] = false;//拆边 
                    init();
                    used[i] = true; //恢复 
                    int x = find2(a), y = find2(b); 
                    if( (r1[x] & r1[y]) == 1 ){
                    //该边被使用,且两个联通块中都包含 基地,所以可以删除,联通块数量+1 
                        t_sum -= edge[i].c; num++;                
                        used[i] = false;                    
                    } 
                } 
            }
        }   
        return sum-t_sum;
    }
    int main(){    
        int T;
        scanf("%d", &T);
        for(int Case = 1; Case <= T; Case++ ){
            scanf("%d%d%d",&n,&t,&k);
            sum = 0;
            for(int i = 0; i < n-1; i++){
                edge[i].input();    
                sum += edge[i].c;
            }
            sort( edge, edge+n-1 );
            memset( used, 0, sizeof(used));
            memset( milit, 0, sizeof(milit));
            for(int i = 0; i < t; i++){
                int x; scanf("%d",&x);    
                milit[x] = true;
            }
            printf("Case %d: %d\n", Case, solve() );
        }
        return 0;
    }
  • 相关阅读:
    centos编辑文件显示行号
    16.1
    [整理]正睿划水记
    [题解]UVA1519 Dictionary Size
    [题解]CF323C Two permutations
    [题解]CF1527D MEX Tree
    P2216 [HAOI2007]理想的正方形
    CF858D Polycarp's phone book
    ABC214F substrings
    每天一点小知识-20210810
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/3036399.html
Copyright © 2011-2022 走看看