BZOJ 3624: [Apio2008]免费道路 [生成树 并查集]
题意:
一张图0,1两种边,构造一个恰有k条0边的生成树
优先选择1边构造生成树,看看0边是否小于k
然后保留这些0边,补齐k条,再加1边一定能构成生成树
类似kruskal的证明
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=2e4+5, M=1e5+5; typedef long long ll; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n, m, k, u, v, c, m0, m1, p; struct meow{int u, v, c;}a[M], b[M], ans[N]; int fa[N]; int find(int x) {return x==fa[x] ? x : fa[x]=find(fa[x]);} int flag[N]; int main() { freopen("in","r",stdin); n=read(); m=read(); k=read(); for(int i=1; i<=m; i++) { u=read(), v=read(), c=read(); if(c==1) a[++m1]=(meow){u,v,c}; else b[++m0]=(meow){u,v,c}; } int cnt=0; for(int i=1; i<=n; i++) fa[i]=i; for(int i=1; i<=m1; i++) { u=a[i].u, v=a[i].v; int x=find(u), y=find(v); if(x==y) continue; fa[x]=y; if(++cnt == n-1) break; } for(int i=1; i<=m0; i++) { u=b[i].u, v=b[i].v; int x=find(u), y=find(v); if(x==y) continue; fa[x]=y; ans[++p]=b[i]; flag[i]=1; if(++cnt == n-1) break; } if(p > k || cnt < n-1) {puts("no solution"); return 0;} for(int i=1; i<=n; i++) fa[i]=i; for(int i=1; i<=p; i++) fa[find(ans[i].u)] = find(ans[i].v); cnt=p; if(cnt<k) for(int i=1; i<=m0; i++) if(!flag[i]){ u=b[i].u, v=b[i].v; int x=find(u), y=find(v); if(x==y) continue; fa[x]=y; ans[++cnt]=b[i]; if(cnt == k) break; } for(int i=1; i<=m1; i++) { u=a[i].u, v=a[i].v; int x=find(u), y=find(v); if(x==y) continue; fa[x]=y; ans[++cnt]=a[i]; if(cnt == n-1) break; } for(int i=1; i<=cnt; i++) printf("%d %d %d\n",ans[i].u, ans[i].v, ans[i].c); }
2017-10-03 今天又写了一下 以前好像有点问题洛谷wa1
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; const int N = 1e5+5, M = 1e5+5; typedef long long ll; inline int read() { char c=getchar(); int x=0,f=1; while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();} return x*f; } int n, m, k; struct edge {int u, v, c;} e[M]; int flag[N], fa[N], ans[N]; int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);} int main() { //freopen("in", "r", stdin); scanf("%d %d %d", &n, &m, &k); for(int i=1; i<=m; i++) e[i].u = read(), e[i].v = read(), e[i].c = read(); for(int i=1; i<=n; i++) fa[i] = i; int num = 0; for(int i=1; i<=m; i++) if(e[i].c == 0) { int f1 = find(e[i].u), f2 = find(e[i].v); if(f1 == f2) continue; fa[f1] = f2; if(++num == n-1) break; } int one = 0; for(int i=1; i<=m; i++) if(e[i].c == 1) { int f1 = find(e[i].u), f2 = find(e[i].v); if(f1 == f2) continue; fa[f1] = f2; one++; ans[++ans[0]] = i; flag[i] = 1; if(++num == n-1) break; } if(one > n-k) {puts("no solution"); return 0;} if(num < n-1) {puts("no solution"); return 0;} for(int i=1; i<=n; i++) fa[i] = i; num = 0; for(int i=1; i<=m; i++) if(e[i].c == 1) { int f1 = find(e[i].u), f2 = find(e[i].v); if(f1 == f2) continue; fa[f1] = f2; if(++num == n-1) break; } int zero = 0; for(int i=1; i<=m; i++) if(e[i].c == 0) { int f1 = find(e[i].u), f2 = find(e[i].v); if(f1 == f2) continue; fa[f1] = f2; zero++; ans[++ans[0]] = i; flag[i] = 1; if(++num == n-1) break; } if(zero > k) {puts("no solution"); return 0;} for(int i=1; i<=n; i++) fa[i] = i; num = ans[0]; for(int i=1, t; i<=ans[0]; i++) t = ans[i], fa[find(e[t].u)] = find(e[t].v); if(zero < k) for(int i=1; i<=m; i++) if(!flag[i] && e[i].c == 0) { int f1 = find(e[i].u), f2 = find(e[i].v); if(f1 == f2) continue; fa[f1] = f2; ans[++ans[0]] = i; ++num; if(++zero == k) break; } if(num < n-1) for(int i=1; i<=m; i++) if(!flag[i] && e[i].c == 1) { int f1 = find(e[i].u), f2 = find(e[i].v); if(f1 == f2) continue; fa[f1] = f2; ans[++ans[0]] = i; if(++num == n-1) break; } if(zero != k || num != n-1) {puts("no solution"); return 0;} for(int i=1, t; i<=ans[0]; i++) t = ans[i], printf("%d %d %d\n", e[t].u, e[t].v, e[t].c); }
Copyright:http://www.cnblogs.com/candy99/