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

 

posted @ 2013-04-22 20:02  yefeng1627  阅读(143)  评论(0编辑  收藏  举报

Launch CodeCogs Equation Editor