POJ 2728 Desert King

最优比率生成树

01 分数规划与MST的结合,注意总成本与总长度比值最小,不等价于总长度与总成本比值最大

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define eps 1e-6
using namespace std;
const int MAXN = 1005;
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, x[MAXN], y[MAXN], hei[MAXN];
double val[MAXN][MAXN], cot[MAXN][MAXN], fin[MAXN][MAXN], l, r, mid, dis[MAXN];
bool f[MAXN];
double cal(int a, int b) {
	return sqrt((double)(x[a] - x[b]) * (x[a] - x[b]) + (y[a] - y[b]) * (y[a] - y[b]));
}
bool chk(double x) {
	memset(f, 0, sizeof(f));
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= n; j++) {
			fin[i][j] = cot[i][j] - x * val[i][j] ;
			//if(x == 1.0) printf("%f ", fin[i][j]);
		}
	}
	double ans = 0.0;
	f[1] = 1;
	for(int i = 1; i <= n; i++) {
		dis[i] = fin[1][i];
	}
	for(int i = 1; i < n; i++) {
		int k = 0;
		double mi = 1e10;
		for(int j = 1; j <= n; j++) {
			if(!f[j]) {
				if(mi > dis[j]) mi = dis[j], k = j;
			}
		}
		if(!k) break;
		f[k] = 1;
		ans += dis[k];
		for(int j = 1; j <= n; j++ ){
			if(!f[j]) {
				if(dis[j] > fin[k][j]) dis[j] = fin[k][j];
			}
		}
	}
	return (ans >= 0.0);
}
int main() {
	while(1) {
		n = init();
		if(!n) break;
		for(int i = 1; i <= n; i++) x[i] = init(), y[i] = init(), hei[i] = init();
		l = r = mid = 0.0;
		for(int i = 1; i <= n; i++) {
			for(int j = 1; j <= n; j++) {
				val[i][j] = cal(i, j);
				r += val[i][j];
				cot[i][j] = (double) abs(hei[i] - hei[j]);
			}
		}
		r = 100.0;
		while(r - l > eps) {
			mid = (l + r) * 0.5;
			if(chk(mid)) {
				l = mid;
			}else r = mid;
		}
		printf("%.3f\n", mid);
	}
	return 0;
}
posted @ 2018-03-29 15:09  Mr_Wolfram  阅读(111)  评论(0编辑  收藏  举报