UVa 1151 Buy or Build (最小生成树)

题目链接

先求出不买套餐的最小生成树的边

然后枚举选择哪些套餐,将套餐中的边权置为 \(0\), 和原先最小生成树的边重新进行 \(kruscal\)

而原先选不到的边,权值大于套餐和最小生成树的边,后来一定也选不到

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1000100;
const int INF = 1000000007;

int T, n, q, cnt, ans;
int c[10];
int x[maxn], y[maxn];
vector<int> Gc[10];

struct Edge{
	int u, v, w;
	
	bool operator < (const Edge& o) const{
		return w < o.w;
	}
}e[maxn];

vector<Edge> E, nE;

int par[maxn], ran[maxn];

int find(int x){
	return par[x] == x ? x : par[x] = find(par[x]);
}

void unite(int x, int y){
	x = find(x), y = find(y);
	if(x == y) return;
	
	if(ran[x] < y){
		par[x] = y;
	} else{
		par[y] = x;
		if(ran[x] == ran[y]) ++ran[x];
	}
}

void kruscal(){
	for(int i = 1 ; i <= n ; ++i) par[i] = i, ran[i] = 1;
	
	int tot = 0;
	for(int i = 1 ; i <= cnt ; ++i){
		if(find(e[i].u) != find(e[i].v)){
			unite(e[i].u, e[i].v);
			++tot;
			
			E.push_back(e[i]);
			if(tot == n - 1){
				break;
			}
		}
	}
}

int use[maxn];

void dfs(int d){
	if(d == q + 1){
		nE.clear();
		int res = 0;
		
		for(auto u : E){
			nE.push_back(u);
		}
		
		for(int i = 1 ; i <= q ; ++i){
			if(use[i]){
				res += c[i]; 
				int u = -1;
				for(auto v : Gc[i]){
					Edge ne;
					if(u != -1){
						ne.u = u;
						ne.v = v;
						ne.w = 0;
						nE.push_back(ne);
						
						u = v;
					} else{
						u = v;
					}
				}
			}
		}
		
		sort(nE.begin(), nE.end());
		
		for(int i = 1 ; i <= n ; ++i) par[i] = i, ran[i] = 1;
		int tot = 0;
		for(auto p : nE){
			if(find(p.u) != find(p.v)){
				unite(p.u, p.v);
				++tot;
				res += p.w;
				
				if(tot == n - 1){
					ans = min(ans, res);
					break;
				}
			}
		} 
		
		return;
	}
	
	use[d] = 1;
	dfs(d + 1);
	
	use[d] = 0;
	dfs(d + 1);
} 

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	scanf("%d", &T);
	int flag = 0;
	while(T--){
		if(flag){
			printf("\n");
		}
		flag = 1;
		
		cnt = 0;
		for(int i = 1 ; i <= q ; ++i) Gc[i].clear();
		E.clear(); 
		memset(use, 0, sizeof(use));
		ans = INF;
		
		scanf("%d%d", &n, &q);
		for(int i = 1 ; i <= q ; ++i){
			int u, v;
			scanf("%d", &u);
			scanf("%d", &c[i]);
			for(int j = 1 ; j <= u ; ++j){
				scanf("%d", &v);
				Gc[i].push_back(v);
			}
		}
		
		for(int i = 1 ; i <= n ; ++i){
			scanf("%d%d", &x[i], &y[i]);
		}
		
		for(int i = 1 ; i <= n ; ++i){
			for(int j = i + 1 ; j <= n ; ++j){
				++cnt;
				e[cnt].u = i, e[cnt].v = j;
				e[cnt].w = (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
			}
		}
		
		sort(e + 1, e + 1 + cnt);
		
		kruscal();
		
		dfs(1); 
		
		printf("%d\n", ans);
	}

	return 0;
}
上一篇:应用能否下线或删除


下一篇:HDU 5293 Tree chain problem (树形dp + 树剖 + LCA)