【題解】LuoGu3623:[APIO2008]免費道路

原題傳送門
轉化題意:求一個有kk條邊是0邊(鵝卵石路)的生成樹
感覺比較套路

先把所有1邊加入,並查集維護連通性,再加入必須加的0邊,統計出多少條,哪幾條0邊是必須要的
如果必須要的0邊>k>k,那麼無解

接下來就重來一次,先把必須加的0邊加入,然後儘可能加到kk條0邊,然後再儘可能加入1邊
如果加入的0邊<k<k,那麼無解

兩次操作之後若不連通也無解
最後就可以輸出了

Code:

#include <bits/stdc++.h>
#define maxn 100010
using namespace std;
struct Line{
	int x, y, type;
}line[maxn], ans[maxn];
int n, f[maxn], m, k, tot, cnt;

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

bool cmp1(Line x, Line y){ return x.type > y.type; }
bool cmp2(Line x, Line y){ return x.type < y.type; }
int getfa(int k){ return k == f[k] ? k : f[k] = getfa(f[k]); }

bool check(){
	int tmp = getfa(1);
	for (int i = 2; i <= n; ++i) if (getfa(i) != tmp) return 1;
	return 0;
}

int main(){
	n = read(), m = read(), k = read();
	for (int i = 1; i <= m; ++i) line[i] = (Line){read(), read(), read()};
	sort(line + 1, line + 1 + m, cmp1);
	for (int i = 1; i <= n; ++i) f[i] = i;
	for (int i = 1; i <= m; ++i){
		int f1 = getfa(line[i].x), f2 = getfa(line[i].y);
		if (f1 == f2) continue;
		f[f1] = f2;
		if (!line[i].type) ++tot, line[i].type = -1;
	}
	if (tot > k || check()) return puts("no solution"), 0;
	sort(line + 1, line + 1 + m, cmp2);
	for (int i = 1; i <= n; ++i) f[i] = i;
	tot = 0;
	for (int i = 1; i <= m; ++i){
		int f1 = getfa(line[i].x), f2 = getfa(line[i].y);
		if (f1 == f2) continue;
		if (line[i].type < 1 && tot < k || line[i].type >= 1) 
			line[i].type = max(line[i].type, 0), tot += 1 - line[i].type, ans[++cnt] = line[i], f[f1] = f2;		
	}
	if (tot < k || check()) return puts("no solution"), 0;
	for (int i = 1; i <= cnt; ++i) printf("%d %d %d\n", ans[i].x, ans[i].y, ans[i].type);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章