目录
显示
题目链接
https://www.luogu.org/problem/P3623
题解
容易看出本题的目标是构造一棵生成树,使得图中边权为 \(0\) 的边恰好有 \(k\) 条。
注意到有些 \(0\) 边是必须在树上的,有些则不是。
我们可以先尝试向生成树中加入所有 \(1\) 边,再尝试插入每一条 \(0\) 边,从而算出至少需要加入的 \(0\) 边数量。
如果至少加入的 \(0\) 边数量大于 \(k\),则无解。
否则前一步插入的 \(0\) 边都将在最终的生成树当中出现。
我们重新跑一遍生成树,将上述的边插入后,我们再尝试将剩下的 \(0\) 边加入生成树中,直到有 \(k\) 条 \(0\) 边为止。
最后把 \(1\) 边插入生成树就可以得出结果了。
#include <cstdio> #include <algorithm> using namespace std; struct edge { int u,v,w; }e[100005]; int fa[20005],res[100005]; bool cmp1(const edge&a,const edge&b) { return a.w>b.w; } bool cmp2(const edge&a,const edge&b) { return a.w<b.w; } int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void unionn(int x,int y) { fa[x]=y; } int main() { int n,m,k; scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); for(int i=1;i<=n;i++) fa[i]=i; sort(e+1,e+m+1,cmp1); int cnt=0; for(int i=1;i<=m;i++) if(find(e[i].u)!=find(e[i].v)) { unionn(find(e[i].u),find(e[i].v)); if(!e[i].w)cnt++,e[i].w=-1; } if(cnt>k) { puts("no solution"); return 0; } for(int i=1;i<=n;i++) fa[i]=i; sort(e+1,e+m+1,cmp2); cnt=0; for(int i=1;i<=m;i++) if(find(e[i].u)!=find(e[i].v)) { if(e[i].w!=1) { if(k)k--; else continue; } unionn(find(e[i].u),find(e[i].v)); res[++cnt]=i; if(e[i].w==-1)e[i].w=0; if(cnt==n-1)break; } if(cnt<n-1||k) { puts("no solution"); return 0; } for(int i=1;i<n;i++) printf("%d %d %d\n",e[res[i]].u,e[res[i]].v,e[res[i]].w); return 0; }