传送门
拉格朗日乘数法裸题
限制
f({v})=∑i=1nkisi(vi−vi′)=EUf(\{v\})=\sum_{i=1}^nk_is_i(v_i-v_i')=E_Uf({v})=i=1∑nkisi(vi−vi′)=EU
求
g({v})=∑i=1n=sivig(\{v\})=\sum_{i=1}^n=\frac{s_i}{v_i}g({v})=i=1∑n=visi
最小值
设
L(λ,{v})=g({v})+λ[f({v})−EU]=∑i=1n[sivi+λkisi(vi−vi′)2]−λEUL(\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_UL(λ,{v})=g({v})+λ[f({v})−EU]=i=1∑n[visi+λkisi(vi−vi′)2]−λEU
对于viv_ivi的偏导数为000,跳若干步后
ki(vi−vi′)vi2=xk_i(v_i-v_i')v_i^2=xki(vi−vi′)vi2=x
二分xxx再二分viv_ivi并计算是否为EUE_UEU即可
#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;
}