每日一题——拔河问题
题目描述
小明班里要举行一次拔河比赛,班主任决定将所有人分为两队,每个人都必须参加。两个队伍的人数之差不能超过1,并且两个队伍的体重之和要尽可能相近,当然相同是最好的了。
输入
输入包含多组测试数据。
每组输入的第一行是一个正整数n(2<=n<=100),表示共有n个人。
接下来n行,每行输入一个整数w(1<=w<=450),表示每个人的体重。
输出
对于每组输入,分别输出两个队伍的体重之和,按升序排序。
样例输入 Copy
3
100
90
200
样例输出 Copy
190 200
因为多了一个限制,也就是分成两队的人数之间的差距不能大于1,所以我们在推导递推式的时候还要考虑总人数的影响,也就是再加一个变量,将其变成二维的,一个代表人数,一个代表总重量。
点击查看代码
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 110, M = 500 * N;
int dp[N][M], a[N], sum;//因为人数相差不能大于1,所以dp要多一个位置用于记录人数
int main()
{
int n, i, j, k;
while (scanf("%d", &n) != EOF)
{
memset(dp, 0, sizeof(dp));
sum = 0;
for (i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
sum += a[i];
}
dp[0][0] = 1;
for (i = 1; i <= n; i++)
{
for (k = sum / 2; k >= a[i]; k--)//k代表总体重
{//不知道为什么k和j不能互换位置
for (j = 1; j <= (n + 1) / 2; j++)//j代表总人数
{
if (dp[j - 1][k - a[i]])//类似于递推,由j-1个人k-a[i]的总体重推到j个人k的总体重
{
dp[j][k] = 1;
}
}
}
}
for (i = sum / 2; i >= 0; i--)//从sum/2开始遍历,左边就会是较小的那个
{
if (dp[n / 2][i] || dp[n / 2 + 1][i])
{
printf("%d %d\n", i, sum - i);
break;
}
}
}
return 0;
}

浙公网安备 33010602011771号