题意:
有多瓶体积一样浓度不一样的药水,要使混合后浓度小于等于w,求可能的体积最大值。
思路:
显然又是一道动态规划。
想了好一会儿数组下标该取什么,如果浓度不是小数的话,取浓度做起来很方便,在0<浓度<=w范围内,dp[浓度] = 混合的瓶数,每次考虑下一瓶的时候对于那些dp值不为0的去和新的一瓶混合,能更新就更新,这样最后最大的瓶数就代表最大的体积。然而浓度是小数。否决。
那么把数组下标取作混合的瓶数怎么样?
这样想了然后就通了然后就写过了。
dp[瓶数] = 浓度和,(因为每一瓶的体积都相同,所以很显然的所有的浓度加起来除以瓶数就是浓度,和体积没有关系,那么在此姑且引入浓度和(误)的概念),一开始不判断浓度是否符合要求,最后从n开始往下找,第一个浓度符合要求的即为体积最大值所在处。
每次考虑下一瓶的时候就是对于前面判断过的所有存在的情况加上新的一瓶的浓度,如果浓度和比当前值小就更新。
状态转移方程为 dp[j] = min(dp[j-1] + p[i]);
AC代码如下:
//2570.cpp
#include <iostream>
#include <iomanip>
#include <cstring>
using namespace std;
#define maxn 110
int p[maxn],ans[maxn];
int main()
{
int T,n,v,w,i,j;
cin >> T;
while (T--)
{
cin >> n >> v >> w;
memset(ans,0,sizeof(ans));
for (i=0;i<n;++i)
cin >> p[i];
ans[0] = 0; //ans[1] = p[0];
for (i=0;i<n;++i)
for (j=n;j>=1;--j)
if (ans[j-1] || j-1==0)
if (ans[j])
ans[j] = min(ans[j],ans[j-1]+p[i]);
else
ans[j] = ans[j-1]+p[i];
/* for (i=0;i<=n;++i)
cout << ans[i] << " ";
cout << endl;*/
i = n;
while (i && ans[i]/(double)i-w>1e-6)
--i;
if (i==0)
cout << "0 0.00\n";
else
cout << i*v << " " << fixed << setprecision(2) << ans[i]/(100.0*i) << endl;
}
return 0;
}