题目大意
一群人拔河,给出每个人的重量,要求两队人数之差不超过1人,且每队总重量之差最小。
思路
选出严格总人数一半(或+1)的人为一队,在该队重量不超过所有人总重量一半的情况下,使其重量最大。
人数一维,最终结果严格为其最大限制:总人数一半;队总重量一维,最终结果尽量大,不一定为其最大限制:所有人总重量一半。
所以初始化时,应将DP数组初始化为-∞,循环结束时,在DP[totV]中求最大值。
#include <cstdio> #include <cstring> #include <algorithm> #include <cstdarg> using namespace std; const int MAX_W = 23000, MAX_V = 55, MAX_ORG = 110; int _max(int a, int b) { return b == 0 ? a : max(a, b); } int Dp(int totV, int totObj, int totW, int *objW) { static int DP[MAX_W][MAX_V]; memset(DP, 0xcf, sizeof(DP)); DP[0][0] = 0; for (int obj = 1; obj <= totObj; obj++) for (int w = totW; w >= objW[obj]; w--) for (int v = totV; v >= 1; v--) DP[w][v] = _max(DP[w][v], DP[w - objW[obj]][v - 1] + objW[obj]); int ans = 0; for (int i = 0; i <= totW; i++) ans = max(ans, DP[i][totV]); return ans; } int main() { #ifdef _DEBUG freopen("c:\noi\source\input.txt", "r", stdin); #endif int n, sum = 0, ws[MAX_ORG]; memset(ws, 0, sizeof(ws)); scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", i + ws); sum += ws[i]; } int lighter = Dp(n / 2, n, (sum + 1) / 2, ws); if ((n / 2) * 2 != n) lighter = max(lighter, Dp(n / 2 + 1, n, (sum + 1) / 2, ws)); int weighter = sum - lighter; if (lighter > weighter) swap(lighter, weighter); printf("%d %d ", lighter, weighter); return 0; }