题目链接:http://codeforces.com/contest/730/problem/J
题目大意:
有n个瓶子。每个瓶子有饮料a[i]。瓶子的体积为b[i]。现在想把所有的饮料倒在k个瓶子里。而且每倒一升的饮料。需要花费时间1。现在希望k最小的情况下并且花费的总时间t最少。
思路:我们可以直接求k。因为要优先满足k。那么就是:
s
o
r
t
(
b
+
1
,
b
+
n
+
1
)
:
∑
i
=
1
k
b
[
i
]
>
=
∑
i
=
1
n
a
[
i
]
sort(b+1, b+n+1):\sum_{i=1}^k b[i] >=\sum_{i=1}^n a[i]
sort(b+1,b+n+1):i=1∑kb[i]>=i=1∑na[i]
直接计算就可以了。
因为我们要把所有的饮料倒在这k个瓶子里面。那么这k个瓶子里面剩余的饮料越多越好。直接dp:
d p [ i ] [ j ] [ k ] : 前 i 个 瓶 子 中 选 择 j 个 瓶 子 , 使 得 这 j 个 瓶 子 的 容 量 为 k , 这 k 个 瓶 子 的 最 多 剩 余 饮 料 dp[i][j][k]:前i个瓶子中选择j个瓶子,使得这j个瓶子的容量为k,这k个瓶子的最多剩余饮料 dp[i][j][k]:前i个瓶子中选择j个瓶子,使得这j个瓶子的容量为k,这k个瓶子的最多剩余饮料
转移方程:
f
(
n
)
=
{
d
p
[
i
]
[
j
]
[
k
]
=
m
a
x
(
d
[
i
−
1
]
[
j
]
[
k
]
,
d
p
[
i
−
1
]
[
k
−
1
]
[
k
−
b
[
i
]
]
+
a
[
i
]
)
,
j>=b[i]
d
p
[
i
]
[
j
]
[
k
]
=
d
[
i
−
1
]
[
j
]
[
k
]
,
j<b[i]
f(n)= \begin{cases} dp[i][j][k]=max(d[i-1][j][k], dp[i-1][k-1][k-b[i]]+a[i]), & \text{j>=b[i]} \\ dp[i][j][k]=d[i−1][j][k], & \text{j<b[i]} \end{cases}
f(n)={dp[i][j][k]=max(d[i−1][j][k],dp[i−1][k−1][k−b[i]]+a[i]),dp[i][j][k]=d[i−1][j][k],j>=b[i]j<b[i]
显然要降维:
#include <bits/stdc++.h>
using namespace std;
int a[105], b[105], c[105], f[105][10005];
int main()
{
int n, m;scanf("%d", &n);
int sum=0, k=0;
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
sum+=a[i];
}
m=sum;//a[]的和
for(int i=1; i<=n; i++){
scanf("%d", &b[i]);
c[i]=b[i];
}
sort(c+1, c+1+n);
for(int i=n; i>=1; i--){//求k
sum-=c[i];
k++;
if(sum<=0){
break;
}
}
memset(f, -1, sizeof(f));
f[0][0]=0;
for(int i=1; i<=n; i++){
for(int j=i; j>=1; j--){
for(int k=10000; k>=b[i]; k--){
if(f[j-1][k-b[i]]!=-1){
f[j][k]=max(f[j][k], f[j-1][k-b[i]]+a[i]);
//cout<<i<<" "<<j<<" "<<k<<" "<<f[j][k]<<endl;
}
}
}
}
int mx=0;
for(int i=m; i<=10000; i++){
mx=max(mx, f[k][i]);
}
printf("%d %d\n", k, m-mx);
return 0;
}