POJ_2728

    最优比率生成树问题,黑书上有详细的介绍,在求的时候可以直接二分K,也可以先假定一个K然后求得一个新的K,如此反复迭代下去。

    对于这个题而言,如果直接二分的话,大概二分50次就可以保证精度了,而迭代的话大概10次就可以保证精度了,所以迭代的效率还是高一些。

View Code 直接二分
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define MAXD 1010
#define INF 0x3f3f3f3f
using namespace std;
int N, vis[MAXD];
double dis[MAXD], x[MAXD], y[MAXD], z[MAXD], bet[MAXD][MAXD];
double sqr(double x)
{
    return x * x;
}
void init()
{
    int i, j;
    for(i = 0; i < N; i ++)
        scanf("%lf%lf%lf", &x[i], &y[i], &z[i]);
    for(i = 0; i < N; i ++)
        for(j = i + 1; j < N; j ++)
            bet[i][j] = bet[j][i] = sqrt(sqr(x[i] - x[j]) + sqr(y[i] - y[j]));
}
double prim(double K)
{
    int i, j, k;
    double m, ans = 0, t;
    memset(vis, 0, sizeof(vis));
    fill(dis, dis + N, INF);
    dis[0] = 0;
    for(i = 0; i < N; i ++)
    {
        m = INF;
        for(j = 0; j < N; j ++)
            if(!vis[j] && dis[j] < m)
                m = dis[k = j];
        vis[k] = 1;
        ans += dis[k];
        for(j = 0; j < N; j ++)
            if(!vis[j] && (t = fabs(z[k] - z[j]) - K * bet[k][j]) < dis[j])
                dis[j] = t;
    }
    return ans;
}
void solve()
{
    int i;
    double min = 0, max = INF, mid, ans;
    for(i = 0; i < 50; i ++)
    {
        mid = (min + max) / 2;
        ans = prim(mid);
        if(ans < 0)
            max = mid;
        else
            min = mid;
    }
    printf("%.3f\n", mid);
}
int main()
{
    for(;;)
    {
        scanf("%d", &N);
        if(!N)
            break;
        init();
        solve();
    }
    return 0;
}
View Code 迭代求解
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define MAXD 1010
#define INF 0x3f3f3f3f
using namespace std;
int N, vis[MAXD], pre[MAXD];
double dis[MAXD], x[MAXD], y[MAXD], z[MAXD], bet[MAXD][MAXD];
double sqr(double x)
{
    return x * x;
}
void init()
{
    int i, j;
    for(i = 0; i < N; i ++)
        scanf("%lf%lf%lf", &x[i], &y[i], &z[i]);
    for(i = 0; i < N; i ++)
        for(j = i; j < N; j ++)
            bet[i][j] = bet[j][i] = sqrt(sqr(x[i] - x[j]) + sqr(y[i] - y[j]));
}
double prim(double K)
{
    int i, j, k;
    double m, zt = 0, lt = 0, t;
    memset(vis, 0, sizeof(vis));
    fill(dis, dis + N, INF);
    dis[0] = 0, pre[0] = 0;
    for(i = 0; i < N; i ++)
    {
        m = INF;
        for(j = 0; j < N; j ++)
            if(!vis[j] && dis[j] < m)
                m = dis[k = j];
        vis[k] = 1;
        lt += bet[pre[k]][k], zt += fabs(z[pre[k]] - z[k]);
        for(j = 0; j < N; j ++)
            if(!vis[j] && (t = fabs(z[k] - z[j]) - K * bet[k][j]) < dis[j])
                dis[j] = t, pre[j] = k;
    }
    return zt / lt;
}
void solve()
{
    int i;
    double ans = 0;
    for(i = 0; i < 10; i ++)
        ans = prim(ans);
    printf("%.3f\n", ans);
}
int main()
{
    for(;;)
    {
        scanf("%d", &N);
        if(!N)
            break;
        init();
        solve();
    }
    return 0;
}
posted on 2012-05-14 11:12  Staginner  阅读(289)  评论(0编辑  收藏  举报