pku 2728 Desert King最有比率生成ツリー

7022 ワード

http://poj.org/problem?id=2728
タイトル:
n個の点の座標の1級の各点に対応する高さを与え、各辺の2つの値、a[i][j]=fabs(h[i]-h[j])の高さ差は修i->jという道にはa[i][j]の費用が必要であり、b[i][j]は道の長さを表す.すべての点が互いに通じ合い、総費用/道路の総長さが最小になるように、道路を修理させます.
考え方:最小比率生成ツリー.このリンクで説明する01スコア計画に従って、最も比率のあるツリーを生成します.
最小生成ツリーの保証を求めて値を最小にするために,二分列挙解を求めた.そしてf(l)==0の解が得られたのが我々の結果である.
#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <queue>

#include <stack>

#include <set>

#include <map>

#include <string>



#define CL(a,num) memset((a),(num),sizeof(a))

#define iabs(x)  ((x) > 0 ? (x) : -(x))

#define Min(a,b) (a) > (b)? (b):(a)

#define Max(a,b) (a) > (b)? (a):(b)



#define ll long long

#define inf 0x7f7f7f7f

#define MOD 1073741824

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)

#define test puts("<------------------->")

#define maxn 100007

#define M 150

#define N 1007

using namespace std;

/*

    freopen("input.txt","r",stdin);

    freopen("output.txt","w",stdout);

*/



//freopen("din.txt","r",stdin);



const double eps = 1e-6;



struct node

{

    double x,y,z;

}p[N];



double dis[N];

bool vt[N];

double a[N][N];

double b[N][N];

int n;



int dblcmp(double x)

{

    if (x > eps) return 1;

    else if (x < -eps) return -1;

    else return 0;

}

void init()

{

    int i,j;

    for (i = 0; i < n; ++i)

    {

        for (j = 0; j < n; ++j)

        {

            a[i][j] = b[i][j] = (i != j)*inf;

        }

    }

}

double prim(double m)

{

    int i,j;

    double res = 0;

    for (i = 0; i <= n; ++i)

    {

        vt[i] = false;

        dis[i] = a[0][i] - m*b[0][i];

    }

    dis[0] = 0; vt[0] = true;

    for (int k = 0; k < n - 1; ++k)

    {

        double MIN = inf;

        for (i = 0; i < n; ++i)

        {

            if (!vt[i] && dis[i] < MIN)

            {

                j = i;

                MIN = dis[i];



            }

        }

        res += MIN;

        vt[j] = true;

        for (i = 0; i < n; ++i)

        {

            double t = a[j][i] - m*b[j][i];//      ,   【j,i】   【i,j】   tle

            if (!vt[i] && b[j][i] != inf && dis[i] > t)

            {

                dis[i] = t;

            }

        }

    }

    return res;

}





int main()

{

     //freopen("input.txt","r",stdin);

    int i,j;



    while (~scanf("%d",&n))

    {

        if (!n) break;

        for (i = 0; i < n; ++i)

        scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);



        init();

        double r = -1;

        for (i = 0; i < n; ++i)

        {

            for (j = 0; j < n; ++j)

            {

               if (i == j) continue;

                double cb = sqrt((p[i].x - p[j].x)*(p[i].x - p[j].x) + (p[i].y - p[j].y)*(p[i].y - p[j].y));

                double ca = iabs(p[i].z - p[j].z);

                b[i][j] = b[j][i] = cb;

                a[i][j] = a[j][i] = ca;

                r = max(r,ca);

            }

        }

        double l = 0;

        double mid = 0;

        while (dblcmp(l - r) < 0)

        {

            mid = (l + r)/2;

            if (prim(mid) >= 0)

            {

                l = mid;

            }

            else r = mid;

        }

        printf("%.3lf
",mid); } return 0; }

  
 Dinkelbach反復アルゴリズムの解決
サブ問題の最適解をprim()ごとに求め,ある範囲内になるまでrを代入する..
#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <queue>

#include <stack>

#include <set>

#include <map>

#include <string>



#define CL(a,num) memset((a),(num),sizeof(a))

#define iabs(x)  ((x) > 0 ? (x) : -(x))

#define Min(a,b) (a) > (b)? (b):(a)

#define Max(a,b) (a) > (b)? (a):(b)



#define ll long long

#define inf 0x7f7f7f7f

#define MOD 1073741824

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)

#define test puts("<------------------->")

#define maxn 100007

#define M 150

#define N 1007

using namespace std;

/*

    freopen("input.txt","r",stdin);

    freopen("output.txt","w",stdout);

*/



//freopen("din.txt","r",stdin);



const double eps = 1e-6;



struct node

{

    double x,y,z;

}p[N];



double dis[N];

bool vt[N];

double a[N][N];

double b[N][N];

int pre[N];

int n;



int dblcmp(double x)

{

    if (x > eps) return 1;

    else if (x < -eps) return -1;

    else return 0;

}

void init()

{

    int i,j;

    for (i = 0; i < n; ++i)

    {

        for (j = 0; j < n; ++j)

        {

            a[i][j] = b[i][j] = (i != j)*inf;

        }

    }

}

double prim(double m)

{

    int i,j;

    double tval = 0,tdis = 0;

    for (i = 0; i <= n; ++i)

    {

        vt[i] = false;

        dis[i] = a[0][i] - m*b[0][i];

        pre[i] = 0;

    }

    dis[0] = 0; vt[0] = true;

    pre[0] = -1;

    for (int k = 0; k < n - 1; ++k)

    {

        double MIN = inf;

        for (i = 0; i < n; ++i)

        {

            if (!vt[i] && dis[i] < MIN)

            {

                j = i;

                MIN = dis[i];



            }

        }

        tval += a[pre[j]][j];//     

        tdis += b[pre[j]][j];//     

        vt[j] = true;

        for (i = 0; i < n; ++i)

        {

            double t = a[j][i] - m*b[j][i];

            if (!vt[i] && b[j][i] != inf && dis[i] > t)

            {

                pre[i] = j;

                dis[i] = t;

            }

        }

    }

    return tval/tdis;//   

}





int main()

{

     //freopen("input.txt","r",stdin);

    int i,j;



    while (~scanf("%d",&n))

    {

        if (!n) break;

        for (i = 0; i < n; ++i)

        scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);



        init();



        for (i = 0; i < n; ++i)

        {

            for (j = 0; j < n; ++j)

            {

               if (i == j) continue;

                double cb = sqrt((p[i].x - p[j].x)*(p[i].x - p[j].x) + (p[i].y - p[j].y)*(p[i].y - p[j].y));

                double ca = iabs(p[i].z - p[j].z);

                b[i][j] = b[j][i] = cb;

                a[i][j] = a[j][i] = ca;

            }

        }

        double s = 0,r = 0;



        while (1)

        {

            r = prim(s);

            if (dblcmp(s - r) == 0) break;

            s = r;

        }

        printf("%.3lf
",r); } return 0; }