其他分享
首页 > 其他分享> > cf730 J. Bottles(01背包变式)

cf730 J. Bottles(01背包变式)

作者:互联网

题意:

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

\(1\le n \le 100, 1\le a_i\le b_i\le 100\)

思路:

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

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

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

转移方程:\(dp[i][j][k]=\max\limits_{1\le i\le n} \{ dp[i-1][j][k],dp[i-1][j-b_i][k-1] + a_i \}\)

第一维可省略,\(j\) 从 \(sumb\) 枚举到 \(b_i\) 。

\(ans = \max \limits _{sumA\le j\le sumb} dp[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;
}

标签:cf730,le,Bottles,int,瓶子,01,sumA,sumb,dp
来源: https://www.cnblogs.com/wushansinger/p/15862532.html