拔河比赛-动态规划

http://www.rqnoj.cn/Problem_72.html

题目:拔河比赛

问题编号:72

题目描述

superwyh的学校要举行拔河比赛,为了在赛前锻炼大家,老师决定把班里所有人分为两拨,进行拔河因为为锻炼所以为了避免其中一方的实力过强老师决定以体重来划分队伍,尽

量保持两个队伍的体重差最少,因为老师对结果没兴趣,所以只告诉老师最小的体重差是多少就行了。这个受苦受累的任务就交给superwyh了,因为这两天superwyh的后背间谍sjh

闹肚子了,所以只好superwyh亲自去调查每个人的体重,但是仅仅知道体重依然难以确定到底如何分配队伍,请各位oier帮助superwyh出出主意。

输入格式

第一行为人数(1<=n<=100),从第二行开始是每个人的体重(0<=m<=100)。

输出格式

最小体重差。

样例输入

4
10
23
41
12

样例输出

4



一、思路


刚开始,我一直想,如果,最后一个人不加,那子问题就成了求解前n-1个人 误差最接近第n个人的体重即可

10 30 60 70 即前3个人组成的两队后,最接近70即可

但是无法建立递推式,前2个人应该和 60 70 0 的子集差值最小的才对

那样就指数级别了


看了题解,将思路转换下,发现好简单

上个思路,有两个同时变化的相关量,即第一队和第二队的变化相互影响


转换为只求一队人的 01背包问题

即所有人的体重 sum / 2 只要让这个n个人里,尽可能的填满大小为sum/2的背包,那么

一队尽可能的由小变大接近均值,那么另外一对肯定是由大到小接近均值,直到这一队无法变大

那么 这时,两者已经尽可能接近了


sum - f[n][sum/2] * 2就是最小差值


二、算法

f[101][5001]来描述,给定i个人,j大小背包时,所能装下的最大重量

height[101] 来保存每个人的重量

f[i][j] = max(f[i-1][j], f[i-1][j-height[i]]);装第i个人或者不装,就只有这两种可能


1、读入n

2、读入每个人的重量,并求出总和sum

3、初始条件:全为0

3、动态规划,二重循环

     第一重:i个人

    第二重:j大小的背包

        f[i][j] = max(f[i-1][j], f[i-1][j-height[i]])


4、输出结果

   sum - f[n][arverage]*2 两者的差值


终于AC

代码如下:

#include <iostream.h>
#include <fstream.h>

int main()
{
    int n, height[101], sum, average, min, i, j;
	static int f[101][5001] = {0};
    //ifstream inFile("e:\\test.txt");
	//读入人数n
    cin>>n;
	//inFile>>n;
   //读入每个人体重
  sum = 0;
  for (i=1; i<=n; i++)
   {
        cin>>height[i];
		//inFile>>height[i];
        sum += height[i];
   }
   average = sum / 2;
   //动态规划
   for (i=1; i<=n; i++)
   {
	   for (j=1; j<=average; j++)
	   {
		   f[i][j] = f[i-1][j];
		   if (j>=height[i] && f[i][j] < f[i-1][j-height[i]]+height[i])
		   {
			   f[i][j] = f[i-1][j-height[i]] + height[i];
		   }
	   }
   }

   //输出结果
  cout<< sum - f[n][average]*2;

  //inFile.close();
    return 0;
}


  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,我无法找到关于Java实现拔河比赛的具体信息。但是,我可以为您介绍一下拔河比赛的一般规则和实现方式。 拔河比赛是一种团队竞技项目,参赛队伍通过拉扯一根绳子来争夺胜利。一般来说,拔河比赛的规则如下: 1. 参赛队伍由一定数量的选手组成,通常是10名选手。 2. 参赛队伍按照身高优先、体重次优先的方式准备比赛阵容。 3. 比赛开始时,选手们站在绳子两端,用力拉扯绳子。 4. 比赛的目标是将对方队伍拉过中线,或者使对方队伍中的选手脚离地面。 5. 比赛结束时,根据谁先达到目标或者拉力的大小来确定胜负。 至于Java的实现方式,可以通过编写一个拔河比赛的类来模拟比赛过程。以下是一个简单的示例代码: ```java public class TugOfWarGame { private Team team1; private Team team2; public TugOfWarGame(Team team1, Team team2) { this.team1 = team1; this.team2 = team2; } public void startGame() { // 实现比赛逻辑 // 比赛开始时,选手们站在绳子两端,用力拉扯绳子 // 判断谁先达到目标或者拉力的大小来确定胜负 } } public class Team { private String name; private List<Player> players; public Team(String name, List<Player> players) { this.name = name; this.players = players; } // 其他相关方法和属性 } public class Player { private String name; private int height; private int weight; public Player(String name, int height, int weight) { this.name = name; this.height = height; this.weight = weight; } // 其他相关方法和属性 } ``` 请注意,以上代码只是一个简单的示例,实际的拔河比赛实现可能会更加复杂。具体的实现方式还取决于您的需求和设计。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值