zoukankan      html  css  js  c++  java
  • NOI2012 骑行川藏 解题报告

      当我还没看别人的解题报告时,我用了三分法做了40%的数据。

      围观大神的解题报告,要通过100%的数据要用到拉格朗日乘数法求得最值。

      Wiki上的解释是这样的:Wikipedia

      Wiki的解释我自己看不太懂,下面这个视频可能让你能对拉格朗日乘数法有更好的认识:麻省理工学院《拉格朗日乘数法》

      下面介绍一下拉格朗日乘数法是如何工作的:

      问题:在g(x1, x2, x3, ..., xn) = c的约束条件下,求f(x1, x2, x3, ..., xn)的最值。

      我们把问题具体化一下:令g(x, y) = xy = 3,f(x, y) = x2 + y2 ,求f(x, y)的最小值。

      我们可以猜到,f(x, y)的最小值是6。

      因为f(x, y)取得最值时受到g(x, y)条件的约束,那么f(x, y)的法向量应当与g(x, y)的法向量相平行。

      于是我们得到下面的方程组:

      fx = λgx  ==> 2x = λy

      fy = λgy  ==> 2y = λx

      g = 3      ==> xy = 3

      解得λ = ±2 ,代入方程组解得 (x, y) = (31/2, 31/2) 或 (x, y) = (-31/2, -31/2)

      如果你还看得不太明白,那么推荐你看看上面的那段视频。

      显然到了现在,你就应该明白这道题是怎么回事了。

      f(v1, v2, v3, ..., vn) = ∑ si / vi 

      g(v1, v2, v3, ..., vn) = ∑ kisi(vi-vi')2

      我们有n+1个方程组:

      -s1 / v12 = 2λk1s1(v1-v1')

      -s2 / v22 = 2λk2s2(v2-v2')

      ...

      -sn / vn2 = 2λknsn(vn-vn')

      g = E

      下面,我们先二分λ的值,再根据上面n个方程依次二分计算出v1, v2, ..., vn的值,代到g(v1, v2, ..., vn)函数中比较g与E的大小,缩小 λ 的范围。

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 
     7 #define N 10001
     8 
     9 using namespace std;
    10 
    11 int n;
    12 double E, s[N], k[N], vp[N], v[N], maxv[N], lamada, ans;
    13 
    14 double getVi(int i, double lam)
    15 {
    16     double left = vp[i], right = maxv[i], mid;
    17     while (right - left >= 1e-13)
    18     {
    19         mid = (left + right) / (double)2;
    20         if (mid == right || mid == left) break;
    21         if (mid * mid * 2 * lam * k[i] * (mid - vp[i]) + 1 > 0) left = mid;
    22         else right = mid;
    23     }
    24     return left;
    25 }
    26 
    27 double balance()
    28 {
    29     double pans = -E;
    30     for (int i=1;i<=n;i++)
    31         pans += s[i] * k[i] * (v[i] - vp[i]) * (v[i] - vp[i]);
    32     return pans;
    33 }
    34 
    35 double getlamada(double left, double right)
    36 {
    37     double mid;
    38     while (right - left >= 1e-13)
    39     {
    40         mid = (left + right) / (double)2;
    41         if (mid == right || mid == left) break;
    42         for (int i=1;i<=n;i++) v[i] = getVi(i, mid);
    43         double ban = balance();
    44         if (ban > 0) right = mid;
    45         else left = mid;
    46     }
    47     return left;
    48 }
    49 
    50 int main()
    51 {
    52     freopen("bicycling.in","r",stdin);
    53     freopen("bicycling.out","w",stdout);
    54     scanf("%d%lf",&n,&E);
    55     for (int i=1;i<=n;i++)
    56     {
    57         scanf("%lf%lf%lf",&s[i],&k[i],&vp[i]);
    58         maxv[i] = vp[i] + sqrtl(E / s[i] / k[i]);
    59     }
    60     lamada = getlamada(-1000, -1e-13);
    61     ans = 0;
    62     for (int i=1;i<=n;i++)
    63         ans += s[i] / v[i];
    64     printf("%.8lf
    ", ans);
    65     return 0;
    66 }
  • 相关阅读:
    windows2008英文版设置文件夹选项
    vmware的使用技巧:将鼠标光标移回所在系统
    java最简代码规范总结
    oracle sql developer工具的使用
    java生成自定义证书图片4
    java生成自定义证书图片3
    java使用resource时,使用try-with-resources代替try-catch-finally
    java中利用BigDecimal进行精确计算
    mybatis分页插件pagehleper的基本使用
    mybatis中mapper映射文件中>=和<=等特殊符号的写法
  • 原文地址:https://www.cnblogs.com/africamonkey/p/3734844.html
Copyright © 2011-2022 走看看