每日一题——拔河问题

题目描述
小明班里要举行一次拔河比赛,班主任决定将所有人分为两队,每个人都必须参加。两个队伍的人数之差不能超过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;
}
posted @ 2023-02-28 19:55  美羊羊给沸羊羊搬砖  阅读(295)  评论(0)    收藏  举报