我猜是哈夫曼算法。。。即贪心把当前连通分量集合中权值最小的两个连接起来,再合成一个加入集合,迭代下去。
来不及交了,先贴下代码。
#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;
}