题意:给定n个点m条边,一开始这些边全都是断的,要修一些边使得n个点全部联通。修完一共可以得到F元,修一条边有成本di和时间ti,要使得 得到的钱数 / 总时间 这个比值最大。

参考资料:

红线内的内容转载自http://www.cnblogs.com/scau20110726/archive/2012/10/19/2730896.html

------------------------------------------------------------------------------------------------------------------

****************************************************

解法之一 0-1分数规划

设x[i]等于1或0, 表示边e[i]是否属于生成树.

则我们所求的比率 r = ∑(benifit[i] * x[i]) / ∑(cost[i] * x[i]), 0≤i<m .

为了使 r 最大, 设计一个子问题---> 让 z = ∑(benifit[i] * x[i]) - l * ∑(cost[i] * x[i]) = ∑(d[i] * x[i]) 最大 (d[i] = benifit[i] - l * cost[i]) , 并记为z(l). 我们可以兴高采烈地把z(l)看做以d为边权的最大生成树的总权值.

然后明确两个性质:

 1.  z单调递减

  证明: 因为cost为正数, 所以z随l的减小而增大.

 2.  z( max(r) ) = 0

  证明: 若z( max(r) ) < 0, ∑(benifit[i] * x[i]) - max(r) * ∑(cost[i] * x[i]) < 0, 可化为 max(r) < max(r). 矛盾;

          若z( max(r) ) >= 0, 根据性质1, 当z = 0 时r最大.

到了这个地步, 七窍全已打通, 喜欢二分的上二分, 喜欢Dinkelbach的就Dinkelbach.

****************************************************

已知一个完全图,每条边有两个参数(dis和c),求一棵生成树,使(∑xi×ci)/(∑xi×disi)最小,其中xi当第i条边包含在生成树中时为1,否则为0。
迭代法:
假设rate为当前比率,以ci-rate×disi作为各边的权重,使用Prim算法构造最小生成树,再对该最小生成树求(∑xi×ci)/(∑xi×disi)更新rate,可证明rate可收敛且收敛值即为所求。
二分法:
在一个精度范围内(以1e-6为例),二分查找[0,maxRate]之间的值rate,使(z=∑xi×ci-rate×∑xi×disi)==0,可证明该值即为所求。其中xi为以ci-rate×disi作为各边权重时,使用Prim算法所构造的最小生成树。在二分搜索过程中若z>0,则将区间上移(low=mid+1),否则将区间下移(high=mid-1)。
使用迭代法,以0作为初始迭代比率:188MS
使用二分法,固定查找范围为[0,31],精度为1e-6:1422MS(不知二分法大家都有什么优化,分享一下吧^_^)

下面介绍一下该题目的解题思路及相关证明:

1、问题转化:

给定一个rate,z(rate)=∑xi×ci-rate*∑xi×disi,xi为一棵生成树使(∑xi×ci-rate*∑xi×disi)的值最小(下面会介绍求此生成树的方

法),则rate=(∑xi×ci-z(rate))/( ∑xi×disi),令rateNex=(∑xi×ci)/( ∑xi×disi)。

若z(rate)>0,则肯定不存在一棵生成树使rate=(∑yi×ci)/( ∑yi×disi),即rate值无效,且有rateNex >rate;

若z(rate)<0,则我们可得到一个有效比率rateNex,且rateNex<rate;

若z(rate)==0,则rateNex==rate,且rate有效。

因此,如果有且仅有一个rate使z(rate)==0,又由题目所求的最小比率的存在性(有限节点的完全图其生成树只有有限个)可知,该rate值即为所求。

下面证明其存在性和唯一性:

存在性:对于题目所求的最小比率rateMin,由上面的分析必有z(rateMin)=0,又由该最小比率的存在性可知,至少存在一个有效的比率rate使z(rate)=0;

唯一性:只要证明z(rate)函数的单调性即可:

对于两个比率rate1<rate2,

z(rate1)-z(rate2)= (∑xi×ci-rate1*∑xi×disi)-(∑yi×ci-rate2*∑yi×disi)

<=(∑yi×ci-rate1*∑yi×disi)-(∑yi×ci-rate2*∑yi×disi)

=(rate2-rate1)* ∑yi×disi>0

因此,z(rate)为单调递减函数。从而也就证明了满足z(rate)==0的比率rate的唯一性。

由上面的分析,我们就将问题转化为求解比率rate使z(rate)==0

2、求解:有两种方法对该问题进行求解:迭代法和二分法。

 A、迭代法:由上面的分析可知:

当 z(rate)>0时,rate值无效,而rateNex有效且z(rateNex)<=0;

当z(rate)<0时,rateNex<rate,又z(rate)为单调递减函数,故0>=z(rateNex)>z(rate)。

故迭代过程向z(rate)==0收敛,又由有限节点的完全图其生成树只有有限个可知迭代次数必为有限值。

 B、二分法:在定出一个搜索范围和精度之后(以[0,MAXRATE]为例),我们就可以使用二分法进行搜索:对于当前的搜索区间[low,high],mid=(low+high)/2,根据z(mid)的值及z(rate)的增减性,对搜索区间进行更新:
                   若z(mid)>0,上调区间,使low=mid+1;

若z(mid)<0,下调区间,使high=mid-1;

从而在经过有限次搜索之后便能找到所求比率。

3、求解生成树xi使(∑xi×ci-rate*∑xi×disi)的值最小的方法:

∑xi×ci-rate*∑xi×disi=∑xi(ci+rate×disi),从而问题转化为以ci+rate×disi为边的权重,求解最小生成树,对于完全图,可使用

prim算法,其复杂度只与节点数有关。

******************************************************************

简单来说(迭代的不是二分)

1.先设比率r=0,对于每条边,我们计算一个新的权值,权值为w[i][j]=c[i][j]-r*d[i][j]  (其中c[i][j]为第i个点和第j个点的垂直高度差,d[i][j]为水平距离,w[i][j]为计算出来的权值)

2.以这个权值去构建最小生成树,用prim算法(时间复杂度只与顶点数有关)去构建。最后统计这个MST的垂直高度差的和sumc,水平距离的和sumd,算出新的比率为R=sumc/sumd;

3.判断新的比率和R和旧的比率r是否相等(精度范围内,这里设为0.00001),如果相等那么R就是答案,否则就r=R(迭代),然后再次去做(1),依次循环直到找到答案

 
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  
 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std; const int N=*,M=*;
const double INF=(double)1e9;
int n,m,len,first[N],fa[N];
bool vis[N];
double F;
struct node{
int x,y,next;
double w,d,t;
bool in;
}a[M]; struct cmpp
{
bool operator () (int &x,int &y)
{
return a[x].w<a[y].w;
}
}; priority_queue<int,vector<int>,cmpp> q; void ins(int x,int y,double d,double t)
{
a[++len].x=x;a[len].y=y;a[len].d=d;a[len].t=t;
a[len].next=first[x];first[x]=len;
} int findfa(int x)
{
if(fa[x]==x) return fa[x];
return findfa(fa[x]);
} double myabs(double x){return x> ? x:-x;} bool cmp(node x,node y){return x.w>y.w;} bool check(double r)
{
int cnt=;
double sum=F;
while(!q.empty()) q.pop();
memset(vis,,sizeof(vis));
for(int i=;i<=len;i++)
{
a[i].w=-a[i].d-r*a[i].t;
a[i].in=;
}
vis[]=;
for(int i=first[];i;i=a[i].next) a[i].in=,q.push(i); while(cnt!=n-)
{
int ind;
while()
{
ind=q.top();q.pop();
int x=a[ind].x,y=a[ind].y;
if(!vis[x])
{
for(int i=first[x];i;i=a[i].next) if(!a[i].in) a[i].in=,q.push(i);
break;
}
if(!vis[y])
{
for(int i=first[y];i;i=a[i].next) if(!a[i].in) a[i].in=,q.push(i);
break;
}
}
cnt++;
vis[a[ind].x]=vis[a[ind].y]=;
sum+=a[ind].w;
}
return (sum>=);
} int main()
{
freopen("a.in","r",stdin);
// freopen("quake.in","r",stdin);
// freopen("quake.out","w",stdout); scanf("%d%d%lf",&n,&m,&F);
len=;
memset(first,,sizeof(first));
for(int i=;i<=m;i++)
{
int x,y;
double d,t;
scanf("%d%d%lf%lf",&x,&y,&d,&t);
ins(x,y,d,t);
ins(y,x,d,t);
} double l=,r=INF,mid;
while(l<r)
{
mid=(l+r)/;
if(check(mid)) l=mid;
else r=mid;
if(myabs(l-r)<=0.000001) break;
}
printf("%.4lf\n",r);
return ;
}

【usaco-Earthquake, 2001 Open】 0-1分数规划 & 最优比率生成树的更多相关文章

  1. poj2728 Desert King(最小生成树+01分数规划=最优比率生成树)

    题意 n个点完全图,每个边有两个权值,求分数规划要求的东西的最小值. (n<=1000) 题解 心态炸了. 堆优化primT了. 普通的就过了. 我再也不写prim了!!!! 咳咳 最优比率生成 ...

  2. 【Earthquake, 2001 Open 】 0-1 分数规划

    71  奶牛施工队一场地震把约翰家园摧毁了,坚强的约翰决心重建家园.约翰已经修复了 N 个牧场,他需要再修复一些道路把它们连接起来.碰巧的是,奶牛们最近也成立了一个工程队,专门从事道路修复.而然,奶牛 ...

  3. poj 2976 Dropping tests 0/1分数规划

    0/1分数规划问题,用二分解决!! 代码如下: #include<iostream> #include<stdio.h> #include<algorithm> # ...

  4. bzoj 3597: [Scoi2014]方伯伯运椰子 0/1分数规划

    3597: [Scoi2014]方伯伯运椰子 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 144  Solved: 78[Submit][Status ...

  5. LOJ 3089 「BJOI2019」奥术神杖——AC自动机DP+0/1分数规划

    题目:https://loj.ac/problem/3089 没想到把根号之类的求对数变成算数平均值.写了个只能得15分的暴力. #include<cstdio> #include< ...

  6. poj2728 Desert King【最优比率生成树】【Prim】【0/1分数规划】

    含[最小生成树Prim]模板. Prim复杂度为$O(n^2),适用于稠密图,特别是完全图的最小生成树的求解.   Desert King Time Limit: 3000MS   Memory Li ...

  7. POJ - 2976 Dropping tests && 0/1 分数规划

    POJ - 2976 Dropping tests 你有 \(n\) 次考试成绩, 定义考试平均成绩为 \[\frac{\sum_{i = 1}^{n} a_{i}}{\sum_{i = 1}^{n} ...

  8. [SDOI2017]新生舞会 0/1分数规划

    ---题面--- 题解: 0/1分数规划,,,但是竟然有诡异的精度问题???因为这个被卡了好久 中途还写过一次KM,,,结果陷入死循环,,,我大概是写了一个假KM,,,于是放弃KM,回来调费用流 这个 ...

  9. bzoj3232圈地游戏——0/1分数规划+差分建模+判环

    Description DZY家的后院有一块地,由N行M列的方格组成,格子内种的菜有一定的价值,并且每一条单位长度的格线有一定的费用. DZY喜欢在地里散步.他总是从任意一个格点出发,沿着格线行走直到 ...

随机推荐

  1. aria2 on ubuntu

    http://www.5yun.org/9102.html http://jpollo.logdown.com/posts/160847-aria2c-and-yaaw aria2c --enable ...

  2. 【week4】技术随笔psp

    本周psp

  3. Vue于React特性简单对比(一)

    一,对象实体对比 vue的对象实体依然是html,而react的对象实体已经变味jsx,一种新的语法结构. vue的html与react的jsx都可以进行拆分,拆分成更细小的组件,组件之间可以传值. ...

  4. Linux系统的性能测试

    性能测试:CPU内存,硬盘IO读写,带宽速度,UnixBench 一.CPU物理个数.内核.超线程.多核心 1.登录Terminal,执行:cat /proc/cpuinfo,就会显示出主机的CPU详 ...

  5. wine update错误 "the cache has no package" error when wine update is available

    网址:https://bugs.launchpad.net/pipelight/+bug/1318321/

  6. IPython 4.0发布:Jupyter和IPython分离后的首个版本

    IPython 4.0日前正式发布,这是IPython分离成IPython和Jupyter后的第一个重要版本. 更新Jupyter的快捷方式是: pip install --upgrade jupyt ...

  7. BZOJ 1050 旅行(并查集)

    很好的一道题.. 首先把边权排序.然后枚举最小的边,再依次添加不小于该边的边,直到s和t联通.用并查集维护即可. # include <cstdio> # include <cstr ...

  8. IntelliJ IDEA2018注册

    第一步:0.0.0.0 account.jetbrains.com及0.0.0.0 www.jetbrains.com  添加到hosts文件 第二步:进入 http://idea.lanyus.co ...

  9. 后缀数组SA学习笔记

    什么是后缀数组 后缀数组\(sa[i]\)表示字符串中字典序排名为\(i\)的后缀位置 \(rk[i]\)表示字符串中第\(i\)个后缀的字典序排名 举个例子: ababa a b a b a rk: ...

  10. CF311B Cats Transport 斜率优化DP

    题面:CF311B Cats Transport 题解: 首先我们观察到山与距离其实是没有什么用的,因为对于任意一只猫,我们都可以直接算出如果有一个人要恰好接走它,需要在哪一时刻出发,我们设第i只猫对 ...