codeforces 730J - Bottles

Nick has n bottles of soda left after his birthday. Each bottle is described by two values: remaining amount of soda ai and bottle volume bi (ai ≤ bi).
Nick has decided to pour all remaining soda into minimal number of bottles, moreover he has to do it as soon as possible. Nick spends x seconds to pour x units of soda from one bottle to another.
Nick asks you to help him to determine k — the minimal number of bottles to store all remaining soda and t — the minimal time to pour soda into k bottles. A bottle can't store more soda than its volume. All remaining soda should be saved.

Input
The first line contains positive integer n (1 ≤ n ≤ 100) — the number of bottles.
The second line contains n positive integers a1, a2, ..., an (1 ≤ ai ≤ 100), where ai is the amount of soda remaining in the i-th bottle.
The third line contains n positive integers b1, b2, ..., bn (1 ≤ bi ≤ 100), where bi is the volume of the i-th bottle.
It is guaranteed that ai ≤ bi for any i.

Output

The only line should contain two integers k and t, where k is the minimal number of bottles that can store all the soda and t is the minimal time to pour the soda into k bottles.


这一题先是计算出所需瓶子的数量,然后就是0-1背包套进去

我原以为三维的三个循环要超时掉,网上有有用两个循环的。

dp[i][k][j]表示前i个取k个恰好b的总和为j时a的总和的最大值。

第i个不屈,dp[i][k][j]=dp[i-1][k][j]

第i个取,dp[i][k][j]=max(dp[i][k][j], dp[i-1][k-1][j-b[i]]+a[i]);


AC代码:

# include <stdio.h>
# include <string.h>
# include <algorithm>                                      
using namespace std;
const int inf=2000000000;
int dp[2][110][10010],sum[110], a[110], b[110], t_b[110];//前n项和 
bool cmp(int a, int b){
	return a>b;
}
int main(){
	int i, j, k, n, l_sum=0, temp, K;
	scanf("%d", &n);
	for(i=1; i<=n; i++){
		scanf("%d", &a[i]);
		l_sum=a[i]+l_sum;
	}
	for(i=1; i<=n; i++){
		scanf("%d", &b[i]);
		t_b[i]=b[i];
		sum[i]=b[i]+sum[i-1];
	}
	sort(b+1, b+n+1, cmp);
	temp=0;
	for(K=1; K<=n; K++){
		temp=temp+b[K];
		if(temp>=l_sum){
		    break;
		}
	}
	for(int i=0; i<2; i++){
		for(int k=0; k<=K; k++){
			for(int j=0; j<=sum[n]; j++){
				dp[i][k][j]=-inf;
			}
		}
	}
	int t=0;
	dp[0][0][0]=dp[1][0][0]=0;
	for(i=1; i<=n; i++, t=t^1){
		for(j=0; j<=sum[i]; j++){
			for(k=1; k<=i&&k<=K; k++){
				dp[t][k][j]=dp[t^1][k][j];
				if(j>=t_b[i]){
					dp[t][k][j]=max(dp[t^1][k-1][j-t_b[i]]+a[i], dp[t][k][j]);
				}
			}
		}
	}
	int res=0;
	t=t^1;
	for(i=l_sum; i<=sum[n]; i++){
		if(dp[t][K][i]>=res){
			res=dp[t][K][i];
		}
	}
	printf("%d %d", K, l_sum-res);
	return  0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值