bzoj2876 骑行川藏

骑行川藏

题目描述
传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=2876

题解
学习了SVM之后发现要用拉格朗日乘子法,然后发现忘光了,于是就补了这题的题解。
关于拉格朗日乘子法的定义可以看上一篇博客https://blog.csdn.net/wcy_1122/article/details/80073067
上面有关于拉格朗日乘子的介绍。

我们可以将题意转化为:在 Σki*(vi-vi')^2*si<=Eu的约束条件下最小化 Σsi/vi
对于给定二次约束并最小化一个函数得问题我们可以使用拉格朗日乘子法解决。

我们写出拉格朗日函数的定义 L(x,λ,v)=f0(x)+Σλi*fi(x)+Σvj*hj(x)
本题只有一个不等式约束条件 Σki*(vi-vi')^2*si-Eu<=0,所以只有一个λ,即λ为一维向量。
所以可以列出拉格朗日函数

L(v,λ) = s1/v1+s2/v2+...+sn/vn + λ*k1*s1*(v1-v1')^2+λ*k2*s2*(v2-v2')^2+...+λ*kn*sn*(vn-vn')^2-λ*Eu

将拉格朗日函数进行对偶化,也就是将拉格朗日函数对于每一个vi求偏导,让其等于零,将vi用其他变量表示然后再带回去。
列出求偏导之后的式子 -si/(vi^2)+2*λ*ki*si*(vi-vi')=0
进行一些简单的化简 2*λ*ki*(vi^2)*(vi-vi')=1

对于本题,由于只有一个λ,所以我们先二分λ,对于二分得到的λ,我们枚举每条道路二分vi使得 2*λ*ki*(vi^2)*(vi-vi')=1=1,再计算总消耗能量是否满足那个不等式约束条件即可。

对于第一个二分,L(x,λ)随λ的减小而增大,是单调的。
对于第二个二分,那个式子是一个关于vi的三次函数,且保证v>vi不然没意义),所以也是单调的,可以二分。

代码

#include<bits/stdc++.h>
#define N 10005
#define inf 1e9
#define eps 1e-12
using namespace std;
int n;double E,k[N],v[N],s[N],x[N],ans;
double pf(double x){return x*x;}
double cal(int i,double p,double mid)
{
  return 2.0*p*k[i]*pf(mid)*(mid-v[i]);
}

double solve(double p)
{
  for(int i=1;i<=n;i++)
  {
    double l=v[i],r=inf;
    while(r-l>eps)
    {
      double mid=(l+r)*0.5;
      if(cal(i,p,mid)>1)r=mid;
      else l=mid;
    }
    x[i]=(l+r)*0.5;
  }
  double sum=0;
  for(int i=1;i<=n;i++)sum+=k[i]*pf(x[i]-v[i])*s[i];
  return sum;
}

int main()
{
  scanf("%d%lf",&n,&E);
  for(int i=1;i<=n;i++)
    scanf("%lf%lf%lf",&s[i],&k[i],&v[i]);
  double l=0,r=inf;
  while(r-l>eps)
  {
    double mid=(l+r)*0.5;
    if(solve(mid)<E)r=mid;
    else l=mid;
  }
  for(int i=1;i<=n;i++)ans+=s[i]/x[i];
  printf("%.8lf\n",ans);
  return 0;
}

猜你喜欢

转载自blog.csdn.net/wcy_1122/article/details/80097249
今日推荐