洛谷 [P3623] 免费道路

有 k 条特殊边的生成树

我们发现有一些边是必须的,如果把所有的水泥路都加入并查集,再枚举鹅卵石路,如果这条路能再次加入并查集,说明这条路是必须的
水泥路同样
这样就把必需边求出来了,剩下就可以随意加边了

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 100005;
int init() {
	int rv = 0, fh = 1;
	char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') fh = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		rv = (rv<<1) + (rv<<3) + c - '0';
		c = getchar();
	}
	return fh * rv;
}
int n, m, nume, head[MAXN], fa[MAXN], k, cnt, ans[MAXN], ind;
struct edge{
	int to, nxt, opt;
}e[MAXN << 1];
void adde(int from, int to, int opt) {
	e[++nume].to = to;
	e[nume].nxt = head[from];
	head[from] = nume;
	e[nume].opt = opt;
}
int find(int x) {
	if(x != fa[x]) return fa[x] = find(fa[x]);
	return fa[x];
}
void merge(int x, int y) {
	int r1 = find(x), r2 = find(y);
	if(r1 != r2) {
		fa[r1] = r2;
	}
}
void input() {
	for(int i = 1; i <= n; i++) fa[i] = i;
}
bool chk() {
	for(int i = 2; i <= n; i++) if(find(i) != find(1)) return 0;
	return 1;
}
int main() {
	n = init(); m = init(); k = init();
	input();
	for(int i = 1; i <= m; i++) {
		int u = init(), v = init(), opt = init();
		adde(u, v, opt); adde(v, u, opt);
		if(opt == 1) merge(u, v);
	}
	for(int i = 1; i <= m * 2; i += 2) {
		if(e[i].opt == 0) {
			int r1 = find(e[i].to), r2 = find(e[((i - 1) ^ 1) + 1].to);
			if(r1 != r2) {
				fa[r1] = r2;
				ans[++cnt] = i;
				ind++;
			}
		}
	}
	if(cnt > k || !chk()) {
		printf("no solution\n"); 
		return 0;
	}
	input();
	for(int i = 1; i <= nume; i += 2) {
		if(e[i].opt == 0) merge(e[i].to, e[((i - 1) ^ 1) + 1].to);
	}
	for(int i = 1; i <= m * 2; i += 2) {
		if(e[i].opt == 1) {
			int r1 = find(e[i].to), r2 = find(e[((i - 1) ^ 1) + 1].to);
			if(r1 != r2) {
				fa[r1] = r2;
				ans[++cnt] = i;
			}
		}
	}
	if(!chk()) {
		printf("no solution\n"); 
		return 0;
	}
	input();
	for(int i = 1; i <= cnt; i++) {
		int t = ans[i];
		merge(e[t].to, e[((t - 1) ^ 1) + 1].to);
	}
	for(int i = 1; i <= nume; i += 2) {
		if(ind == k) break;
		if(e[i].opt == 0) {
			int r1 = find(e[i].to), r2 = find(e[((i - 1) ^ 1) + 1].to);
			if(r1 != r2) {
				fa[r1] = r2;
				ans[++cnt] = i;
				ind++;
			}
		}
	}
	if(ind != k) {
		printf("no solution\n"); 
		return 0;
	}
	for(int i = 1; i <= nume; i += 2) {
		if(e[i].opt == 1) {
			int r1 = find(e[i].to), r2 = find(e[((i - 1) ^ 1) + 1].to);
			if(r1 != r2) {
				fa[r1] = r2;
				ans[++cnt] = i;
			}
		}
	}
	sort(ans + 1, ans + cnt + 1);
	for(int i = 1 ; i <= cnt; i++) {
		int t = ans[i];
		printf("%d %d %d\n", e[((t - 1) ^ 1) + 1].to, e[t].to, e[t].opt);
	}
	return 0;
}
posted @ 2018-04-28 11:37  Mr_Wolfram  阅读(147)  评论(1编辑  收藏  举报