#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 60;
int w[N], f[N * N], s[N]; // **注意01背包里f里是价值**
int ans;
int main ()
{
for(int i = 0; i < 4; i ++) cin >> s[i]; //注意分别读入,放入下面的for里是错的
for(int i = 0; i < 4; i ++)
{
memset(f, 0, sizeof f); //每次要清空f
int sum = 0;
for(int j = 0; j < s[i]; j ++) cin >> w[j], sum += w[j];
for(int j = 0; j < s[i]; j ++)
for(int k = sum / 2; k >= w[j]; k --)
f[k] = max(f[k], f[k - w[j]] + w[j]);
ans += sum - f[sum / 2];
}
cout << ans;
return 0;
}
显然若当前要处理的问题的时间和为sum,最佳答案是sum / 2,也就是两边脑所耗时间差为0。
于是现在要求的问题就是使得两边脑所耗时间差尽量小。
如果只考虑一边脑耗时,由于两边脑是对称的,我们假设这个耗时肯定比 sum / 2 小。那么我们要使这个耗时尽量接近sum / 2 , 则另一边脑肯定也是最接近 sum / 2的
两个脑子分别放题目,我们使它消耗的时间最接近 sum / 2 ,则答案最优
所以可以用01背包,将每个科目所有题目的时间总和的一半看成背包容量,花费时间看成体积和价值,求出最大值,此时这个最大值是小于等于 sum / 2 的 , 则就是最接近 sum / 2方案,则 sum - f [ sum / 2 ] 就是这一个科目花费的最少时间,(因为f [ sum / 2 ] 是小于等于 t / 2 的最大值,则 n - f [ sum / 2 ] 就肯定大于等于 sum / 2),用全局变量ans 加起来