POJ 2576 Tug of War 二维费用背包

本文探讨了如何通过分组背包算法解决拔河比赛中两队体重总和最接近的问题,介绍了解题思路与具体实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

http://poj.org/problem?id=2576

题意:

有n个人参加分为两队参加拔河比赛,每个人有一个体重。要求两队的体重和只差最小,且人数相差不得超过1,分别求两队的总体重,先输出较小的

思路:

分组背包问题。题目有两个限制因素:体重和人数。设总体重为sum,那么应该求n/2(n为奇数求n/2和n/2+1)的人在不超过sum/2时所能达到的最大体重。 定义 dp[i][j][k] 为前i个人体重为选出k个人所达到的不超过j的最大体重,得状态转移方程为 dp[i][j][k]=max(dp[i1][j][k],dp[i1][jw][k1]+v) ,可以优化空间把第一维优化掉。注意初始应该把dp数组初始化为-1,把dp[0][0][0]初始化为0,这是因为当dp[i-1][j-w][k-1]这个状态没有从其他状态到达时,那么实际这个状态就只有1个人而不是k-1个人,于是状态就错了,在从这里转移的话, 导致后面的都出错,所以不能从这里转移到dp[i][j][k],所以初始只有dp[0][0][0]是合法的状态。另外n为奇数时,两队人数不同, 无法确定哪队能达到不超过体重一半的最大值,所以两队都要求,取其中的较大值。代码附数据一组,答案为6 12,很多代码过不了

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 110, INF = 0x3f3f3f3f;
int v[N];
int dp[N*250][N];

int work(int n, int m, int r)
{
    memset(dp, -1, sizeof dp);
    dp[0][0] = 0;
    for(int i = 1; i <= n; i++)
        for(int j = m; j >= v[i]; j--)
            for(int k = r; k >= 1; k--)
                if(dp[j-v[i]][k-1] != -1)
                    dp[j][k] = max(dp[j][k], dp[j-v[i]][k-1] + v[i]);

    for(int i = m; i >= 0; i--)
    {
        if(n & 1)
        {
            if(dp[i][r-1] != -1 || dp[i][r] != -1) return i;
        }
        else
        {
            if(dp[i][r-1] != -1) return i;
        }
    }
}
int main()
{
    int n;
    while(~ scanf("%d", &n))
    {
        int sum = 0;
        for(int i = 1; i <= n; i++) scanf("%d", &v[i]), sum += v[i];
        int res = work(n, sum/2, n/2+1);
        printf("%d %d\n", min(res, sum-res), max(res, sum-res));
    }
    return 0;
}
//4
//9 3 3 3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值