【bzoj2876】 Noi2012—騎行川藏


 http://www.lydsy.com/JudgeOnline/problem.php?id=2876 (題目鏈接)

題意

  在滿足約束條件$${\sum_{i=1}^ns_ik_i(v_i-v_i')^2=E}$$

  求$${min\sum_{i=1}^n\frac{s_i}{v_i}}$$

Solution

  像這種形式的存在一個多元函數${g(v_1,v_2,v_3,······,v_n)=E}$的約束,求解多元函數${f(v_1,v_2,v_3,······,v_n)}$的最值,我們使用拉格朗日乘子法。

  在解這道題之前,我們要知道什么是偏導數,梯度向量,等高線等等一系列的東西。當然我是不知道的,只能靠自己YY了。如果這些你都知道了,那么你應該就會知道到當${f}$取到最值時,${f}$和${g}$的等高線相切→_→,既然它們的等高線相切,那么它們的梯度向量平行${\nabla f~//~\nabla g}$。

  梯度向量的每一維就是這個函數對應那一維的偏導數$${\nabla f=(\frac{\partial f}{\partial v_1},\frac{\partial f}{\partial v_2},\frac{\partial f}{\partial v_3}······,\frac{\partial f}{\partial v_n})}$$

  因為${f}$和${g}$的梯度向量平行,我們只要知道它們在哪一個點平行,我們就解出了${v_1···v_n}$。設${\nabla f=\lambda \nabla g}$,我們可以列出${n+1}$個等式。

$${\frac{\partial f}{\partial v_1}=\lambda \frac{\partial g}{\partial v_1}}$$

$${\frac{\partial f}{\partial v_2}=\lambda \frac{\partial g}{\partial v_2}}$$

$${\frac{\partial f}{\partial v_3}=\lambda \frac{\partial g}{\partial v_3}}$$

$${······}$$

$${\frac{\partial f}{\partial v_n}=\lambda \frac{\partial g}{\partial v_n}}$$

$${g(v_1,v_2,v_3,······,v_n)=E}$$

  求出偏導數代入。

$${-\frac{s_1}{v_1^2}=2\lambda k_1s_1(v_1-v_1')}$$

$${-\frac{s_2}{v_2^2}=2\lambda k_2s_2(v_2-v_2')}$$

$${-\frac{s_3}{v_3^2}=2\lambda k_3s_3(v_3-v_3')}$$

$${······}$$

$${-\frac{s_n}{v_n^2}=2\lambda k_ns_n(v_n-v_n')}$$

$${\sum_{i=1}^nk_i(v_i-v_i')^2s_i=E}$$

  化簡一下。

$${2\lambda k_1v_1^2(v_1-v_1')=-1}$$

$${2\lambda k_2v_2^2(v_2-v_2')=-1}$$

$${2\lambda k_3v_3^2(v_3-v_3')=-1}$$

$${······}$$

$${2\lambda k_nv_n^2(v_n-v_n')=-1}$$

$${\sum_{i=1}^nk_i(v_i-v_i')^2s_i=E}$$

  考慮${v_i}$的范圍。如果對應的${v_i'<0}$,吹的是逆風,那么${v_i>0}$;如果${v_i'>0}$,吹的是順風,那么讓${v_i=v_i'}$一定優於${v_i<v_i'}$,於是我們得到了${v_i}$的下界。${v_i}$的上界就是把所有的能量全部用在這一段路上所能達到的最大速度(然而程序里面上界不能這樣寫,數據有幾個點存在${s_i=0}$的情況,smg嘛→_→)。

  知道了${v_i}$的下界,那么顯然${k_iv_i^2(v_i-v_i')>0}$,所以${\lambda<0}$。所以${v_i}$隨着${\lambda}$的增大而增大,而${\sum_{i=1}^nk_i(v_i-v_i')^2s_i}$隨着${v_i}$的增大而增大。所以我們二分${\lambda}$,進而二分求解${v_i}$,把${v_i}$代入函數${g}$,與${E}$比較比較大小來判斷${\lambda}$的范圍是應該往上還是往下。

細節

  公式不要寫錯,精度把握好。

代碼

// bzoj2876
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf 2147483640
#define eps 1e-13
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=100010;
long double s[maxn],k[maxn],v[maxn],vp[maxn],maxv[maxn],Eu;
int n;

long double check(long double lambda) {
	long double tmp=0;
	for (int i=1;i<=n;i++) {
		long double l=max((long double)0.0,vp[i]),r=maxv[i];v[i]=l;
		while (l<=r) {
			long double mid=(l+r)/2;
			if (2*lambda*mid*mid*k[i]*(mid-vp[i])>=-1) l=mid+eps,v[i]=mid;
			else r=mid-eps;
		}
		tmp+=k[i]*(v[i]-vp[i])*(v[i]-vp[i])*s[i];
	}
	return tmp<=Eu;
}
int main() {
	scanf("%d%LF",&n,&Eu);
	for (int i=1;i<=n;i++) {
		scanf("%Lf%Lf%Lf",&s[i],&k[i],&vp[i]);
		//maxv[i]=vp[i]+sqrt(Eu/k[i]/s[i]);
		maxv[i]=inf;
	}
	long double l=-inf,r=0,lambda;
	while (l<=r) {
		long double mid=(l+r)/2;
		if (check(mid)) l=mid+eps,lambda=mid;
		else r=mid-eps;
	}
	check(lambda);
	long double ans=0;
	for (int i=1;i<=n;i++) ans+=s[i]/v[i];
	printf("%.6Lf",ans);
	return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM