题解:UVA10482 The Candyman Can
问题
$T$ 组数据,每组数据给你 $n$ 个数,把这 $n$ 个数分成三个部分,问总和最大与最小的差值最小是多少。
思路
考虑到 $n \le 32$,直接暴力枚举。
优化:枚举两个部分,第三个部分可以通过总和与前两个部分相减求出。
设 $f_{i, j}$ 为第一个部分总和为 $i$,第二个部分总和为 $j$ 的第三个部分是否可行。
那么开始暴力枚举,如果 $f_{i, j}$ 可以,那么第三部分加上这个数也可以。
代码
#include <bits/stdc++.h>
using namespace std;
int T, n, ans, sum, a[35];
bool f[105][105];
int main()
{
cin >> T;
for (_ = 1; _ <= T; _++) // 使用 while(T--) _++; 也可以
{
ans = INT_MAX, sum = 0;
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
sum += a[i];
}
memset(f, 0, sizeof(f));
f[0][0] = 1;
for (int i = 1; i <= n; i++)
{
for (int j = sum; j >= 0; j--)
{
for (int k = sum; k >= 0; k--)
{
if (f[j][k]) // 如果可以
{
f[j + a[i]][k] = true; // 那么加上这个数也可以
f[j][k + a[i]] = true; // 反存
}
}
}
}
for (int i = 0; i <= sum; i++)
{
for (int j = 0; j <= sum; j++)
{
if (f[i][j]) // 可行
{
int x = min(min(i, j), sum - i - j); // 总和最小的分组
int y = max(max(i, j), sum - i - j); // 总和最大的分组
ans = min(ans, y - x); // 记录差值最小的答案
}
}
}
printf("Case %d: %d\n", _, ans); // 使用 cout << "Case " << _ << ": " << ans << endl; 也可以
}
return 0;
}