【NOI2012】骑行川藏【拉格朗日乘数法】【二分套二分】

传送门

拉格朗日乘数法裸题

限制

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=1nkisi(vivi)=EU

g ( { v } ) = ∑ i = 1 n = s i v i g(\{v\})=\sum_{i=1}^n=\frac{s_i}{v_i} g({v})=i=1n=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=1n[visi+λkisi(vivi)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(vivi)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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值