POJ 2728 Desert King (最小最优比率生成树+01规划的应用)

原题地址: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;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81322761
今日推荐