POJ 2728 Desert King 最优比例生成树

本文介绍了一种利用二分法和迭代法求解最小费用流问题的方法,通过调整费用比例来逐步逼近最优解,适用于解决特定类型的网络流问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://poj.org/problem?id=2728

二分版 代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define sf scanf
#define pf printf
#define dpow(x) ((x) * (x))
#define esp 1e-5
#define INF 1e10
using namespace std;
const int maxn = 1000 + 5;

double A[maxn][maxn],B[maxn][maxn],D[maxn][maxn];
double x[maxn],y[maxn],h[maxn];

double dis[maxn];
bool vis[maxn];
double PRIME(int n,double l){
    memset(vis,0,sizeof vis);
    for(int i = 0;i < n;++i)
        for(int j = 0;j < n;++j) D[i][j] = D[j][i] = A[i][j] - l * B[i][j];
    for(int i = 0;i < n;++i) dis[i] = D[0][i];
    dis[0] = 0;vis[0] = 1;dis[n] = INF;
    int p;double tmp = 0;
    for(int i = 0;i < n - 1;++i){
        p = n;
        for(int j = 0;j < n;++j)
            if(!vis[j] && dis[j] < dis[p]) p = j;
        vis[p] = 1;tmp += dis[p];
        for(int j = 0;j < n;++j)
            if(!vis[j] && dis[j] > D[p][j]) dis[j] = D[p][j];
    }
    return tmp;
}
int main(){
    int n;
    while( sf("%d",&n) && n ){
        for(int i = 0;i < n;++i) sf("%lf %lf %lf",&x[i],&y[i],&h[i]);
        for(int i = 0;i < n;++i){
            for(int j = i;j < n;++j){
                A[i][j] = A[j][i] = fabs(h[i] - h[j]);
                B[i][j] = B[j][i] = sqrt( dpow(x[i] - x[j]) + dpow(y[i] - y[j]) );
            }
        }
        double l = 0,r = 100,mid;
        while(l + esp < r){
            mid = (l + r) / 2.0;
            if(PRIME(n,mid) < 0)  r = mid;
            else l = mid;
        }
        pf("%.3f\n",mid);
    }
}

迭代版
代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define sf scanf
#define pf printf
#define dpow(x) ((x) * (x))
#define esp 1e-5
#define INF 1e10
using namespace std;
const int maxn = 1000 + 5;

double A[maxn][maxn],B[maxn][maxn],D[maxn][maxn];
double x[maxn],y[maxn],h[maxn];

double dis[maxn];
int fa[maxn];
bool vis[maxn];
double PRIME(int n,double l){
    memset(vis,0,sizeof vis);
    for(int i = 0;i < n;++i)
        for(int j = 0;j < n;++j) D[i][j] = D[j][i] = A[i][j] - l * B[i][j];
    for(int i = 0;i < n;++i) dis[i] = D[0][i],fa[i] = 0;
    vis[0] = 1;dis[n] = INF;
    int p;double up = 0,low = 0;
    for(int i = 0;i < n - 1;++i){
        p = n;
        for(int j = 0;j < n;++j)
            if(!vis[j] && dis[j] < dis[p]) p = j;
        vis[p] = 1;up += A[fa[p]][p],low += B[fa[p]][p];
        for(int j = 0;j < n;++j)
            if(!vis[j] && dis[j] > D[p][j]) dis[j] = D[p][j],fa[j] = p;
    }
    return up / low;
}
int main(){
    int n;
    while( sf("%d",&n) && n ){
        for(int i = 0;i < n;++i) sf("%lf %lf %lf",&x[i],&y[i],&h[i]);
        for(int i = 0;i < n;++i){
            for(int j = i;j < n;++j){
                A[i][j] = A[j][i] = fabs(h[i] - h[j]);
                B[i][j] = B[j][i] = sqrt( dpow(x[i] - x[j]) + dpow(y[i] - y[j]) );
            }
        }
        double ans = 0,tmp = 10;
        while(fabs(ans - tmp) > esp){
            ans = tmp;
            tmp = PRIME(n,tmp);
        }
        pf("%.3f\n",ans);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值