拉格朗日乘数法裸题
限制
f ( { v } ) = ∑ i = 1 n k i s i ( v i − v i ′ ) = E U f(\{v\})=\sum_{i=1}^nk_is_i(v_i-v_i')=E_U f({v})=i=1∑nkisi(vi−vi′)=EU
求
g ( { v } ) = ∑ i = 1 n = s i v i g(\{v\})=\sum_{i=1}^n=\frac{s_i}{v_i} g({v})=i=1∑n=visi
最小值
设
L ( λ , { v } ) = g ( { v } ) + λ [ f ( { v } ) − E U ] = ∑ i = 1 n [ s i v i + λ k i s i ( v i − v i ′ ) 2 ] − λ E U L(\lambda,\{v\})=g(\{v\})+\lambda[f(\{v\})-E_U]\\=\sum_{i=1}^n[\frac{s_i}{v_i}+\lambda k_is_i(v_i-v_i')^2]-\lambda E_U L(λ,{v})=g({v})+λ[f({v})−EU]=i=1∑n[visi+λkisi(vi−vi′)2]−λEU
对于 v i v_i vi的偏导数为 0 0 0,跳若干步后
k i ( v i − v i ′ ) v i 2 = x k_i(v_i-v_i')v_i^2=x ki(vi−vi′)vi2=x
二分 x x x再二分 v i v_i vi并计算是否为 E U E_U EU即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAXN 10005
using namespace std;
double s[MAXN],k[MAXN],v[MAXN],v_[MAXN],E;
int n;
inline double solve(int i,double x)
{
x/=k[i];
double l=0,r=1e5,mid;
for (int T=1;T<=100;T++)
{
mid=(l+r)/2;
if ((mid-v_[i])*mid*mid<x) l=mid;
else r=mid;
}
return v[i]=l;
}
inline bool check(double x)
{
double sum=0;
for (int i=1;i<=n;i++)
{
solve(i,x);
sum+=k[i]*s[i]*(v[i]-v_[i])*(v[i]-v_[i]);
}
return sum<E;
}
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=1e5,mid;
for (int i=1;i<=100;i++)
{
mid=(l+r)/2;
if (check(mid)) l=mid;
else r=mid;
}
double ans=0;
for (int i=1;i<=n;i++) ans+=s[i]/solve(i,l);
printf("%.8f",ans);
return 0;
}