Codeforces Round #212 (Div. 2) D. Fools and Foolproof Roads

我猜是哈夫曼算法。。。即贪心把当前连通分量集合中权值最小的两个连接起来,再合成一个加入集合,迭代下去。

来不及交了,先贴下代码。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
#include<string>
#include<cmath>
#include<fstream>
#include<iomanip>

using namespace std;

#define LL long long
#define MAXN 111111
int n, m, u[MAXN], v[MAXN], w[MAXN];
int p, q, f[MAXN<<1];
LL fw[MAXN<<1];

int finds(int x){
    if(f[x] == -1) return x;
    else return (f[x] = finds(f[x]));
}
#define cint const int
#define inf 1e15

bool cmp(cint a, cint b){
    return fw[a] < fw[b];
}

int t[MAXN], ans1[MAXN], ans2[MAXN];
queue<int> ori, noi;

bool have(int &n1, int &n2){
    bool f = false;
    int q1=-1, q11=-1, q2=-1, q22=-1;
    if(!ori.empty()){
        q1 = ori.front();  ori.pop();
        if(!ori.empty()) q11 = ori.front();
    }
    if(!noi.empty()){
        q1 = noi.front();   noi.pop();
        if(!noi.empty()) q22 = noi.front();
    }
    if(q1<0 || q2<0) return false;
    LL a1 = fw[q1] + fw[q2], a2 = (q11 > -1 ? fw[q1]+fw[q11] : inf),
       a3 = (q22 > -1 ? fw[q2] + fw[q22] : inf);
    LL mn = min(min(a1, a2), a3);
    if(a1 == mn){
        n1 = q1;
        n2 = q2;

    }
    else if(a2 == mn){
        ori.pop();  n1=q1;  n2=q11;
    }
    else{
        noi.pop();  n1=q2;  n2=q22;
    }
    return true;
}

int mp[MAXN<<1];
void getans(int cnt){
    int i, j=0;
    for(i=1; i<=n; i++) if(f[i]==-1)
        t[j++] = i;
    sort(t, t+j, cmp);
    int mx = n + 1;
    while(!ori.empty()) ori.pop();      while(!noi.empty()) noi.pop();
    for(i=0; i<cnt; i++) ori.push(t[i]);
    for(i=0; cnt>q && p;){
        int n1, n2;
        if(have(n1, n2)){
            f[n1] = n2;
            LL t1 = (fw[n2] + fw[n1]) * 2 + 1, t2 = 1e9;
            fw[n2] = min(t1, t2);
            fw[mx] = fw[n2];
            mp[mx] = n2;
            noi.push(mx);
            if(n1 > n) n1 = mp[n1];
            if(n2 > n) n2 = mp[n2];
            ans1[i] = n1, ans2[i] = n2;
            cnt--;    i++;
            p--;        mx++;
        }
        else break;
    }
    if(p){
        int a1=-1, a2=-1;
        for(j=1; j<=n; j++) if(f[j]>-1){
            if(a1==-1) a1=j;
            else{ a2=j; break;}
        }
        while(p--)  ans1[i]=a1, ans2[i++]=a2;
    }
    for(j=0; j<i; j++) printf("%d %d\n", ans1[j], ans2[j]);
}

int main(){
    //freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
    while(scanf(" %d %d %d %d", &n, &m, &p, &q)==4){
        int i, j, cnt = n;
        for(i=0; i<m; i++) scanf(" %d %d %d", &u[i], &v[i], &w[i]);
        fill_n(f, n<<1, -1);
        fill_n(fw, n+1, 0);
        for(i=0; i<m; i++){
            int x = finds(u[i]), y = finds(v[i]);
            if(x != y){
                f[x] = y;
                fw[y]+=w[i];
                cnt--;
            }
        }
        if(cnt < q || cnt - p > q || (cnt==n && q==n && p)){
            printf("NO\n");     continue;
        }
        printf("YES\n");
        getans(cnt);
    }
    return 0;
}

 

posted @ 2013-11-15 01:36  Ramanujan  阅读(301)  评论(0编辑  收藏  举报