poj3296--Rinse(三分)

来源:互联网 发布:多益网络 收入 编辑:程序博客网 时间:2024/06/05 05:08

题目链接:点击打开链接

题目大意:有一个酒桶容量为Vc,里面还有Vw的酒,现在用Vb的水去刷酒桶,每次酒桶的内壁上会留下Vr的液体,最多可以刷k次,问怎么样刷酒桶,可以让酒桶里面的就最少。

如果Vb+Vw < Vc,那么直接输出0

那么其它情况就保证了一定可以向外倒水。所以最终的桶里面剩余的液体是Vr,只要保证Vr内的酒的浓度最小,那么剩余的酒也就是最少的。

可以假设用的水是x1,x2,x3,,,,计算每次刷通后的浓度。

第一次刷:Vw / (Vw+x1)

第二次刷:Vw / (Vw+x1) * Vr / (Vr+x2)

第三次刷:Vw / (Vw+x1) * Vr / (Vr+x2)* Vr / (Vr+x3)

这样也就能看出来,如果洗刷k次,那么最终的浓度是Vw / (Vw+x1)* Vr / (Vr+x2) * Vr / (Vr+x3),,,,* Vr / (Vr+xk)

那么如何保证它的值最小呢?如果我们能确定一个x1,那么x2+x3,,,+xk = Vb-x1,这样的条件怎么保证Vr / (Vr+x2) * Vr / (Vr+x3),,,,* Vr / (Vr+xk)尽量小,我们可以发现,如果x2 = x3 = x4 ,, = xk计算出的结果会比不同的更小,如果x的值都是(Vb-x1)/(k-1),那么k越大,得到的值就越小。(Vb-x1)/(k-1)越大,那么得到的值越小。

所以选择最多的刷洗次数,从第2次到第k次,每次用水相同,那么剩下的就是x1怎么确定。

如果x1增加,那么Vw / (Vw+x1)会减小,(Vb-x1)/(k-1)会减小,(Vr/(Vr+x))^(k-1)就会增大,总的浓度不能确定,所以用三分查找,找到一个最小的结果。

注意

1、三分的时候桶内的就有Vw,注意三分的上下界。

2、在计算浓度的时候,向桶内加的水由Vb-x算出,但是这个值不能超多Vc-Vr

#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>using namespace std ;#define eqs 1e-9int k ;double vb , vw , vr , vc ;double solve(double x) {    double ans = vw/(vw+x) ;    if( k > 1 ) {        double y = min( (vb-x)/(k-1), vc-vr) ;        for(int i = 1 ; i < k ; i++)            ans *= vr/(vr+y) ;    }    return ans ;}int main() {    while( scanf("%d", &k) != EOF ) {        if(k == 0) break ;        scanf("%lf %lf %lf %lf", &vb, &vw, &vr, &vc) ;        if( vr-vw-vb > eqs ) {            printf("0\n") ;            continue ;        }        double low = max(0.0,vr-vw) , mid1 , mid2 , high = min(vb,vc-vw) ;        while( low + eqs < high ) {            mid1 = (low + high)/2.0 ;            mid2 = (mid1 + high)/2.0 ;            if( solve(mid1) > solve(mid2) ) {                low = mid1 ;            }            else                high = mid2 ;        }        printf("%d", k) ;        printf(" %.2f", high) ;        if( k > 1 ) high = min(vc-vr,(vb-low)/(k-1)) ;        for(int i = 1 ; i < k ; i++) {            printf(" %.2f", high) ;        }        printf("\n") ;    }    return 0 ;}


0 0
原创粉丝点击