拉格朗日乘数法

题目

在无穷大的水平面上有一个平面直角坐标系。N-1条垂直于x轴的直线将空间分为了N个区域。

你被要求把 (0,0) ( 0 , 0 ) 处的箱子匀速推到 (x,y) ( x , y )

箱子受水平面的摩擦力与正压力正相关,所以在每个区域的摩擦力可以表示为 fi f i

那么,你把箱子推到目的地做的最小功是多少呢?(不考虑改变速度时的做功)

拉格朗日乘数法

所谓拉格朗日乘数法,就是现在我有若干变量: x1,x2,x3,x4...xn x 1 , x 2 , x 3 , x 4 . . . x n ,有条件 G(x)=K G ( x ) = K ,然后要求最大/小化一个函数 F(x) F ( x )
这样的话,只要整出一个变量 lambda l a m b d a ,然后对于函数 L(x)=F(x)lambda(G(x)K) L ( x ) = F ( x ) − l a m b d a ( G ( x ) − K ) ,对于包括 lambda l a m b d a 在内的所有变量求偏导,当所有的偏导数都是0的时候, F(x) F ( x ) 取到最值。

解题思路

本题中, F(x)=ni=1fid2i+y2i F ( x ) = ∑ i = 1 n f i d i 2 + y i 2 G(x)=ni=1yi=Y G ( x ) = ∑ i = 1 n y i = Y ,发现我们可以二分 λ λ ,由于对每个 yi y i 求偏导的结果都要是0。使用复合函数求导的方法,将 L(x) L ( x ) xi x i 求偏导的结果是 fiyid2i+y2i f i y i d i 2 + y i 2 ,可以得到 yi=λdif2iλ2 y i = λ d i f i 2 − λ 2 ,发现本式具有单调性,将求解出来的 yi y i 相加,看比 Y Y 大还是小,就可以知道二分的这个λ大了还是小了。
最后算一下 F(x) F ( x )

#include<bits/stdc++.h>
using namespace std;
#define RI register int
typedef double db;
const int N=105;
const db eps=1e-7;
int n;db d[N],f[N],Y,ans;
int check(db u) {
    db y=0;
    for(RI i=1;i<=n;++i) y+=d[i]*u/sqrt(f[i]*f[i]-u*u+1e-9);
    return y>Y;
}
int main()
{
    db l,r=1e20,res=0;
    scanf("%d%lf",&n,&Y);
    for(RI i=1;i<=n;++i) scanf("%lf",&d[i]);
    for(RI i=1;i<=n;++i) scanf("%lf",&f[i]),f[i]=1/f[i],r=min(r,f[i]);
    l=-r;
    while(r-l>eps) {
        db mid=(l+r)/2.0;
        if(check(mid)) res=mid,r=mid;
        else l=mid;
    }
    for(RI i=1;i<=n;++i) ans+=d[i]*f[i]*sqrt(1+res*res/(f[i]*f[i]-res*res));
    printf("%.3lfn",ans);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值