拔河比赛

题意

一个学校举行拔河比赛,所有的人被分成了两组,每个人必须(且只能够)在其中的一组,要求两个组的人数相差不能超过1,且两个组内的所有人体重加起来尽可能地接近。  


分析

这道题目不满足动态规划最优子结构的特性。因为最优子结构要求一个问题的最优解只取决于其子问题的最优解。就这道题目而言,当前n-1个人的分组方案达到最优时,并不意味着前n个人的分组方案也最优。但题目中标注出每个人的最大体重为450,这就提醒我们可以从这里做文章,否则的话,命题者大可把最大体重标注到长整型。假设w[i]表示第i个人的体重。f[i,j,k]表示在前i个人中选j个人在一组,他们的重量之和等于k是否可能。显然,f[i,j,k]是boolean型,其值为true代表有可能,false代表没有可能。那f[i,j,k]与什么有关呢?从前i个人中选出j个人的方案,不外乎两种情况:⑴第i个人没有被选中,此时就和从前面i-1个人中选出j个人的方案没区别,所以f[i,j,k]与f[i-1,j,k]有关。⑵第i个人被选中,则f[i,j,k]与f[i-1,j-1,k-w[i]]有关。综上所述,可以得出:

f[i,j,k]=f[i-1,j,k] or f[i-1,j-1,k-w[i]]。

这道题占用的空间看似达到三维,但因为i只与i-1有关,所以在具体实现的时候,可以把第一维省略掉。另外在操作的时候,要注意控制j与k的范围(0<=j<=i/2,0<=k<=j*450),否则有可能超时。

这种方法的实质是把解本身当作状态的一个参量,把最优解问题转化为判定性问题,用递推的方法求解。这种问题有一个比较明显的特征,就是问题的解被限定在一个较小的范围内,如这题中人的重量不超过450。



var
n,i,j,k,n2,t,tj,min:longint;
f:array[0..50,0..450*50]of boolean;
w:array[0..100]of longint;
begin
    readln(n);
    tj:=0;n2:=(n+1) div 2;
    for i:=1 to n do
    begin
        readln(w[i]);
        tj:=w[i]+tj;
    end;
    fillchar(f,sizeof(f),0);
    f[0,0]:=true;
    for i:=1 to n do
    for j:=n2-1 downto 0 do
    for k:=450*i downto 0 do
    if f[j,k] then f[j+1,k+w[i]]:=true;
    min:=maxlongint;
    t:=0;
    for i:=0 to n2*450 do
    if (f[n2,i]=true)and(abs(tj-i-i)<min) then
    begin
        min:=abs(tj-i-i);
        if i<=tj div 2 then t:=i else t:=tj-i;
    end;
    write(t,' ',tj-t);


end.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值