您的位置:首页 > 其它

poj 2728 Desert King 二分+O(n^2)最小生成树验证

2011-08-14 18:36 417 查看
什么情况 今天才听说printf标准输出double的要%.f 不是%.lf

。。。

这是什么情况啊谭浩强那本绿书加上他的红书乃至杭电自己的黄皮书和图书馆偷来的肉色书都没有写这个啊以前一直都是printf %.lf啊太坑了啊

怎么这个就一直Wrong Anwser呢。。。

这个求一个最小比例的生成树 也就是说每条边有2个权 h和l 要求出一个生成树 满足sigma(h)/sigma(l)最小

以前就只学过最小生成树 当时只会那个什么k什么算法 就是把边权从小到大排序 这个还是第一次看到

开始想了几个贪心的方法 同学也想了 经过实践和"推翻"操作... 不行啊

后面才想到可以二分均值 然后去验证

均值好二分 就是2个浮点数head tail mid=(head+tail)/2.0

怎么验证呢?

这里我稍稍用了点数学知识

验证sigma(h)/sigma(l)==K
均值K可取

即: sigma(h)==K*sigma(l)

sigma(h)==K*(l1+l2+l3+...lm)

sigma(h)==K*l1+K*l2+K*l3+...K*lm

令li'=K*li

则sigma(h)==l1'+l2'+l3'+...lm'

看到这里应该可以明白了

把原来的每个边的h都减去K*l

即hi'=hi-li'==hi-li*K

然后问题可以转换到求hi'这些边的最小生成树了

可以仔细想想这样转换是正确的

如果hi'这些边得最小生成树权值和<=0.0

说明K这个均值可取...

因为减掉li*K之后生成树<=0.0了

如果加回去 也就是每个边都+回去li*K

那么总的会+sigma(l)*K

我们要求的又是sigma(h)/sigma(l)==[sigma(h')+sigma(l)*K]/sigma(l)==sigma(h')/sigma(l)+ K >=K

现在这个K是不是单独分离出来了呢 所以这里就证明了如果h'的最小生成树<=0.0 k这个均值就可取的 题目要求

取最小的均值 那么就可以把均值进一步减小 然后进一步二分 直到精度符合题目要求

while tail-head>1e-4

begin

mid=(head+tail)/2.0;

验证r=(mid)

if r<=0.0 then tail=mid;

else head=mid;

end;

最后就是输出用%.3f\n

刚开始我最小生成树验证的时候超时了

我用的那个先把边排序的算法 由于这个题边很多 两两点之间都有

O(log(INF)*m*logm) 超时了

后面改成prim算法

O(log(INF)*n^2)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>

using namespace std;
#define MAXN 1010
#define INF 2000000000
typedef double elem_t;

struct Point
{
double x,y;
double h;
};

Point node[MAXN];
double mat[MAXN][MAXN];
double h[MAXN][MAXN];
double l[MAXN][MAXN];
int pre[MAXN];
int n;

double head,tail;

inline double dist(Point &a,Point &b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

elem_t prim(int n,elem_t mat[][MAXN],int* pre)
{
elem_t min[MAXN],ret=0;
int v[MAXN],i,j,k;
for (i=0;i<n;i++)
min[i]=INF,v[i]=0,pre[i]=-1;
for (min[j=0]=0;j<n;j++)
{
for (k=-1,i=0;i<n;i++)
if (!v[i]&&(k==-1||min[i]<min[k]))
k=i;
for (v[k]=1,ret+=min[k],i=0;i<n;i++)
if (!v[i]&&mat[k][i]<min[i])
min[i]=mat[pre[i]=k][i];
}
return ret;
}
int main()
{
int i,j;

while(~scanf("%d",&n) && n)
{
double maxc=-INF,minc=INF;
double maxl=-INF,minl=INF;
for(i=0;i<n;i++)
{
scanf("%lf %lf %lf",&node[i].x,&node[i].y,&node[i].h);
}
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
{
h[i][j]=h[j][i]=fabs(node[i].h-node[j].h);
l[i][j]=l[j][i]=dist(node[i],node[j]);
if(maxc<h[i][j])
maxc=h[i][j];
if(minc>h[i][j])
minc=h[i][j];
if(maxl<l[i][j])
maxl=l[i][j];
if(minl>l[i][j])
minl=l[i][j];
}

head=minc/maxl;
tail=maxc/minl;
double mid;

while(tail-head>1e-4)
{
mid=(head+tail)/2.0;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
{
mat[i][j]=mat[j][i]=h[i][j]-mid*l[i][j];
}
if(prim(n,mat,pre)<=0.0)
tail=mid;
else
head=mid;
}
printf("%.3f\n",head);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: