原题地址:http://poj.org/problem?id=2728
题意:题意:有n个点,有三个属性代表每个点在平面上的位置,和它的高度。点与点之间有一个花费:两点的高度差;还有一个长度:两点的距离。现在要让你在这n个点里面弄一个生成树,使得∑cost / ∑dis 最小,问最小的比率是多少。
思路:还是推几篇大佬的博客
https://blog.csdn.net/Jianzs_426/article/details/77899313
下面贴上我的ac代码
#include <cmath>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <cctype>
#define eps 1e-5
#define INF 0x3f3f3f3f
#define MOD 1e9+7
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define CLR(x,y) memset((x),y,sizeof(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1005;
double cost[maxn][maxn];
double dis[maxn][maxn];
int n;
struct node { //记录村庄信息
int x, y, z;
} e[maxn];
double get_dis(node a, node b) {
double p = (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
return sqrt(p);
}
int vis[maxn];
int pre[maxn];//表示节点的前驱节点,用于知道在最小生成树加入的都是什么边(由哪两个顶点组成)
double dis2[maxn];//用于在最有比例生成树中记距离
double prim(double mid) {
CLR(vis, 0);
dis2[1] = 0;
double totdis = 0, totcost = 0;
for(int i = 1; i <= n; i++) pre[i] = 1;
for(int i = 2; i <= n; i++) dis2[i] = cost[1][i] - mid * dis[1][i];
vis[1] = 1; //
for(int i = 1; i <= n - 1; i++) {
double MIN = INF;
int u = 0;
for(int j = 2; j <= n; j++) {
if(vis[j]) continue;
if(MIN > dis2[j]) {//选择一个最小的
u = j;
MIN = dis2[j];
}
}
vis[u] = 1;
for(int j = 2; j <= n; j++) {
if(vis[j]) continue;
if(dis2[j] > cost[u][j] - mid * dis[u][j]) {
dis2[j] = cost[u][j] - mid * dis[u][j] ;//更新pre和dis2
pre[j] = u;
}
}
}
for(int i = 2; i <= n; i++) {//每次加入的边通过pre记录下来,然后等形成一棵树后,再最后相加
totcost += cost[i][pre[i]];
totdis += dis[i][pre[i]];
}
return totcost / totdis;
}
int main() {
while(~scanf("%d", &n), n) {
for(int i = 1; i <= n; i++) {
scanf("%d%d%d", &e[i].x, &e[i].y, &e[i].z);
}
for(int i = 1; i <= n; i++) {
for(int j = i ; j <= n; j++) {
if(i == j) {
dis[i][i] = 0;
cost[i][i] = 0;
continue;
}
dis[i][j] = dis[j][i] = get_dis(e[i], e[j]);//计算距离
cost[i][j] = cost[j][i] = abs(e[i].z - e[j].z);//计算花费
}
}
double ans = 0, tmp = 0;
while(1) {
ans = prim(tmp);//迭代法求值
if(abs(ans - tmp) < eps) break;
tmp = ans;
}
printf("%.3f\n", ans);
}
return 0;
}