POJ 2728 Desert King (最优比率生成树 01分数规划问题)

来源:互联网 发布:中科恒业医学软件 编辑:程序博客网 时间:2024/05/18 02:45
题意:
在这么一个图中求一棵生成树,这棵树的单位长度的花费最小是多少?
 
思路:
 
最小生成树的表达式可以这样写
∑x[i]*dis[i]-minsum>=0;(x[i]为0或者1,要求为一棵生成树)
 
这个题目ans<=(∑cost[i]*x[i])/(∑dis[i]*x[i]).变形可得∑x[i]*(cost[i]-dis[i]*ans)-0>=0;cost[i]-dis[i]*ans就相当于最小生成树中的dis[i];
二分ans,check的时候跑一边prime算法看得到的最小生成树的和是否>=0,最后可得答案;

#include <cstdio>#include <iostream>#include <cstring>#include <string>#include <cstdlib>#include <algorithm>#include <cmath>#include <vector>#include <set>#include <list>#include <queue>#include <map>using namespace std;#define L(i) i<<1#define R(i) i<<1|1#define INF  0x3f3f3f3f#define pi acos(-1.0)#define eps 1e-9#define maxn 100010#define MOD 1000000007struct node{    int x,y,z;}a[1010];int n;double mp[1010][1010];double dis[1010],lowcost[1010];int nearvex[1010];double get_dis(int i,int j){    return sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));}int prim(double mid){    int k = 0;    double sum = 0;    for(int i = 1; i <= n; i++)    {        lowcost[i] = abs(a[1].z - a[i].z) - mp[1][i] * mid;        nearvex[i] = 1;    }    nearvex[1] = -1;    for(int i = 1; i <= n; i++)    {        int v = -1;        double Min = INF;        for(int j = 1; j <= n; j++)            if(nearvex[j] != -1 && lowcost[j] < Min)        {            v = j;            Min = lowcost[j];        }        if(v != -1)        {            nearvex[v] = -1;            sum += lowcost[v];            for(int j = 1; j <= n; j++)                if(nearvex[j] != -1 && abs(a[v].z - a[j].z)-mp[v][j]*mid < lowcost[j])            {                lowcost[j] = abs(a[v].z - a[j].z)-mp[v][j]*mid;                nearvex[j] = v;            }        }    }    return sum < 0;}int main(){    int t,C = 1;    //scanf("%d",&t);    while(scanf("%d",&n) && n)    {        for(int i = 1; i <= n; i++)            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);        for(int i = 1; i <= n; i++)            for(int j = i; j <= n; j++)                mp[i][j] = mp[j][i] = get_dis(i,j);        double l = 0,r = 100;        while(r - l > 0.00001)        {            double mid = (l + r) / 2;            if(prim(mid))                r = mid;            else                l = mid;        }        printf("%.3f\n",l);    }    return 0;}



0 0
原创粉丝点击