POJ 3925 Minimal Ratio Tree(枚举+最小生成树)

POJ 3925 Minimal Ratio Tree

题目链接

题意:给定一些点权和一个边权矩阵,求一个最小的比例的树

思路:先枚举用哪些点,然后求最小生成树即可

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 20;

int n, m, val[N], edge[N][N];

int bitcount(int x) {
	if (x == 0) return 0;
	return bitcount(x>>1) + (x&1);
}

struct Edge {
	int u, v, w;
	Edge() {}
	Edge(int u, int v, int w) {
		this->u = u;
		this->v = v;
		this->w = w;
	}
} e[N * N];

int en;

bool cmp(Edge a, Edge b) {
	return a.w < b.w;
}

int parent[N];

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

int cal() {
	sort(e, e + en, cmp);
	for (int i = 0; i < n; i++) parent[i] = i;
	int tot = n;
	int ans = 0;
	for (int i = 0; i < en; i++) {
		int pu = find(e[i].u);
		int pv = find(e[i].v);
		if (pu != pv) {
			parent[pu] = pv;
			ans += e[i].w;
			tot--;
		}
		if (tot == 1) break;
	}
	return ans;
}

int main() {
	while (~scanf("%d%d", &n, &m) && n || m) {
		for (int i = 0; i < n; i++) scanf("%d", &val[i]);
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				scanf("%d", &edge[i][j]);
		int maxs = (1<<n);
		int anss;
		double ans = 1e15;
		for (int i = 1; i < maxs; i++) {
			if (bitcount(i) != m) continue;
			int sumnode = 0;
			en = 0;
			for (int u = 0; u < n; u++) {
				if (i&(1<<u)) {
					sumnode += val[u];
					for (int v = 0; v < n; v++) {
						if (edge[u][v] == 0) continue;
						if (i&(1<<v)) e[en++] = Edge(u, v, edge[u][v]);
					}
				}
			}
			double tmp = cal() * 1.0 / sumnode;
			if (ans > tmp) {
				ans = tmp;
				anss = i;
			}
		}
		int bo = 0;
		for (int i = 0; i < n; i++) {
			if (anss&(1<<i)) {
				if (bo) printf(" ");
				else bo = 1;
				printf("%d", i + 1);
			}
		}
		printf("\n");
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值