【POJ 2728】[01分数规划]Desert King

来源:互联网 发布:php curl 编码 编辑:程序博客网 时间:2024/06/05 00:44

题意

给出n,表示点数,对于每一个点给出三个属性x,y,h。
要求求出一颗生成树,使得边的费用和与长度和之比ΣaiΣbi最小。
边的费用就是ai=abs(hihj),长度为bi=(xixj)2+(yiyj)2

题目解析

这道题就是最小比值生成树,可以用01规划来实现
点此看01规划板题
只是这里的贪心不一样,我们先重新计算边权,因为我们要尽可能的让比值最小,也就是让生成树的权值最小要小于0才能让ans在当前区间,于是我们用Prim算法(不是Kruskal(要T)也不是Prime)求一发最小生成树。

代码

#include<cstdio>#include<iostream>#include<cstring>#include<cmath>#include<queue>#include<algorithm>using namespace std;#define MAXN 1000#define MAXM#define INF 0x3f3f3f3ftypedef long long int LL;template<class T>void Read(T &x){    x=0;char c=getchar();bool flag=0;    while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();}    while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}    if(flag)x=-x;}const double EPS = 1e-4;int Sign(const double x){    if(x>EPS)return 1;    else if(x<-EPS)return -1;    else return 0;}double a[MAXN+10][MAXN+10];double b[MAXN+10][MAXN+10];double d[MAXN+10][MAXN+10];double dist[MAXN+10];bool vis[MAXN+10];int n;double Prim(){    for(int i=1;i<=n;++i)dist[i]=1e18;    memset(vis,0,sizeof(vis));    dist[1]=0;    double ans=0;    int x;double dmin;    for(int i=1;i<=n;++i){        x=-1,dmin=1e18;        for(int j=1;j<=n;++j)            if(!vis[j]&&Sign(dmin-dist[j])>0)x=j,dmin=dist[j];        ans+=dmin;        vis[x]=1;        for(int j=1;j<=n;++j)            if(!vis[j]&&Sign(dist[j]-d[x][j])>0)dist[j]=d[x][j];    }    return ans;}bool check(double l){    for(int i=1;i<=n;++i)        for(int j=1;j<=n;++j)            d[i][j]=a[i][j]-l*b[i][j];    return Sign(Prim())<=0;}double x[MAXN+10],y[MAXN+10];double h[MAXN+10];int main(){    while(~scanf("%d",&n)&&n){        for(int i=1;i<=n;++i)            scanf("%lf%lf%lf",&x[i],&y[i],&h[i]);        for(int i=1;i<=n;++i)            for(int j=1;j<=n;++j){                a[i][j]=fabs(h[i]-h[j]);                b[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));            }        double l=0,r=10000000,mid;        while(r-l>EPS){            mid=(l+r)/2.0;            if(check(mid))r=mid;            else l=mid;        }        printf("%0.3lf\n",l);    }}
1 0
原创粉丝点击