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