• 拔河比赛


    题意

    一个学校举行拔河比赛,所有的人被分成了两组,每个人必须(且只能够)在其中的一组,要求两个组的人数相差不能超过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.

  • 相关阅读:
    codevs 1569 最佳绿草

    luogu P3378 【模板】堆
    cogs 762. [USACO Open09] 奶牛队列
    各种 Python 实现的简单介绍与比较
    与 的区别
    Python3 print()函数sep,end,file参数用法练习
    python基础
    servlet篇 之 跳转问题
    servlet篇 之 servlet的访问
  • 原文地址:https://www.cnblogs.com/YYC-0304/p/9500161.html
Copyright © 2020-2023  润新知