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;

}

 

你可能感兴趣的:(you)