cf730 J. Bottles(01背包变式)

题意:

给定n个瓶子,初始第 i 个瓶子装有水 ai,容积为 bi。要把所有水装进尽量少的瓶子里,其次使要转移的水量最小。输出要用的瓶子数 K 和要转移的水量 ans

1n100,1aibi100

思路:

所有瓶子中的水量总和为 sumA 。按容积对所有瓶子从大到小排序,第 1K 个瓶子的容积和 sumb 恰大于等于 sumA ,输出 K

n 个瓶子中选 K 个。要使要转移的水量最小,则要使选出的 K 个瓶子中初始的水的总和最大。

dp[i][j][k] 表示在前 i 个瓶子中选 k 个,这 k 个瓶子的容积之和为 j,这 k 个瓶子的最大初始水总和。

转移方程:dp[i][j][k]=max1in{dp[i1][j][k],dp[i1][jbi][k1]+ai}

第一维可省略,jsumb 枚举到 bi

ans=maxsumAjsumbdp[j][K] ,初始化 dp[0][0]=0,其他为负无穷

const int N = 110;
struct node {int a, b; } c[N];
bool cmp(node x, node y) {return x.b > y.b; } //按b逆序
int n, sumA, sumb, K, ans, f[N*N][N];

signed main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &c[i].a), sumA += c[i].a;
    for(int i = 1; i <= n; i++) scanf("%d", &c[i].b);

    sort(c + 1, c + 1 + n, cmp);
    while(sumb < sumA) sumb += c[++K].b;
    printf("%d ", K);

    memset(f, -0x3f, sizeof f), f[0][0] = 0;
    for(int i = 1; i <= n; i++)
        for(int j = sumb; j >= c[i].b; j--)
            for(int k = 1; k <= K; k++)
                f[j][k] = max(f[j][k], f[j-c[i].b][k-1] + c[i].a);

    for(int j = sumA; j <= sumb; j++) ans = max(ans, f[j][K]);
    cout << sumA - ans;
}

posted @   Bellala  阅读(91)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示