[HNOI2006]公路修建问题 题解+代码
[HNOI2006]公路修建问题
期望20,实际10 没想到,居然在我的骗分代码上删了两个if后就A了,神奇?!!
分析
其实就是一个两次生成树,我考场上可能有一点问题居然想了kruskal+DP让后再想到了有限制的生成树等各种奇特的算法。因为看到必须要有k条生成树的边中是第一类,并且c1>=c2,所以直接先对c1进行排序,然后再对他求半棵生成树,一棵有k条边的生成树,然后再构成剩下n-k-1条边的半棵生成树,注意,此时的排序应该是c2的权值进行排序,应为此时构成的边是c2权值。让后就直接在求生成树的时候max一下,求一下最大的权值,让后输出,了事。
code
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 2e4 + 5; int n,k,m,fa[MAXN]; struct node{ int a,b,c1,c2; }p[MAXN]; void Make_Set() { for(int i = 1;i <= m;i ++) fa[i] = i; } int Find_Set(int x) { if(fa[x] == x) return x; return fa[x] = Find_Set(fa[x]); } int Sum; bool cmp1(node x,node y){ return x.c2 < y.c2;} bool cmp2(node x,node y){ return x.c1 < y.c1;} void Kruskal() { sort(p + 1,p + m,cmp1); for(int i = 1;i < m;i ++) { int x = Find_Set(p[i].a),y = Find_Set(p[i].b); if(x == y) continue; fa[x] = y; Sum = max(Sum,p[i].c2); } printf("%d",Sum); } void kruskal() { sort(p + 1,p + m,cmp2); int q = 0; for(int i = 1;i < m;i ++) { int x = Find_Set(p[i].a); int y = Find_Set(p[i].b); if(x == y) continue; fa[x] = y; Sum = max(Sum,p[i].c1); q ++; if(q == k) break; } } int main() { scanf("%d %d %d",&n,&k,&m); for(int i = 1;i <= m - 1;i ++) scanf("%d %d %d %d",&p[i].a,&p[i].b,&p[i].c1,&p[i].c2); Make_Set(); kruskal(); Kruskal(); return 0; }