算法导论之动态规划 签约棒球自由球员

假设你是一支棒球大联盟球队的总经理。在赛季休季期间,你需要签入一些自由球员。球队老板给你的预算为X美元,你可以使用少于X美元来签入球员,但如果超支,球队老板就会解雇你。

你正在考虑在N个不同位置签入球员,在每个位置上,有P个该位置的自由球员供你选择。由于你不希望任何位置过于臃肿,因此每个位置最多签入一名球员(如果在某个特定位置上你没有签入任何球员,则意味着计划继续使用现有球员)

为了确定一名球员的价值,你决定使用一种称为“VORP”,或“球员替换价值”的统计评价指标。球员的VORP值越高,其价值越高。但VORP值高的球员签约费用并不一定比VORP值低的球员高,因为还有球员价值之外的因素影响签约费用。

对于每个可选择的自由球员,你知道他的三方面信息:

1.他打哪个位置。2.他的签约费用。3.他的VORP

设计一个球员选择算法,是的总签约费用不超过X美元,而球员的总VORP最大。你可以假定每位球员的签约费用是10万美元的整数倍。算法应输出签约球员的总VORP值,总签约费用,以及球员名单。分析算法的时间和空间复杂度。

 

问题分析:此题是一规划问题,类似与背包问题,想深入理解这一系列问题的人可以去看看大神讲的背包九讲。

在解决问题的方法论上,总结寻找规律,是最好的一种方法了。如下表:

费用 位置

10

20

30

40

50

60

70

80

90

100

110

1

1

1

1

1

1

1

1

1

1

1

1

2

2

3

3

3

3

3

3

3

3

3

3

3

0

4

5

5

5

5

5

5

5

5

5

4

3

4

7

7

7

7

7

7

7

7

7

5

5

 

 

 

 

 

 

 

 

 

 

6

3

 

 

 

 

 

 

 

 

 

 

7

3

 

 

 

 

 

 

 

 

 

 

8

0

 

 

 

 

 

 

 

 

 

 

9

0

 

 

 

 

 

 

 

 

 

 

10

0

 

 

 

 

 

 

 

 

 

 

11

1

 

 

 

 

 

 

 

 

 

 

如果尝试去填写这一张表,大家就会发现其中的规律,也会明白为什么这个题可以用动态规划算法去求解。上表的规律可以总结如下几点:

1.从上到下,从左至右求解

2.求解中有许多重叠的子问题,如单元格(430)的求解等于(420)与(320)与(410)的求解。

我们可以从中发现动态规划问题的两大特点:最优子结构与重叠子问题,都是满足的。



#include <iostream>
#define total_pos 10
#define max_money 200
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
typedef struct {

    int cost;
    int vorp;
} player;
int main()
{
    //输入部分
    int vorp[11][max_money+1]={-1};// 浪费空间,网友可以好好修改下,vorp[i][j]表示前i个位置在j美元限制下最大的vorp;
    player baseball[11][7];  // baseball[i][j]表示第i个位置第j个候选人;
    cout<<"****** cos*******vorp"<<endl;
    for(int i=1;i<=10;i++)
        for(int j=1;j<=6;j++)
    cin>>baseball[i][j].cost>>baseball[i][j].vorp;
    //输入部分结束
    //算法初始化部分
    for(int j=10;j<=max_money;j=j+10)
    {
         baseball[1][0].vorp=-1;
        for(int k=1;k<=7;k++)
        if(baseball[1][k].cost<=max_money&&baseball[1][k].vorp>=baseball[1][k-1].vorp)
          {
              vorp[1][j]=baseball[1][k].vorp;
          }
    }
    //算法初始化部分结束
    //递归实现部分
    for(int i=2;i<=10;i++)
        for(int j=10;j<=max_money;j+=10)
        {
            baseball[i][0].vorp=-1;
            for(int k=1;k<=6;k++)
        {
              if(j-baseball[i][k].cost>0&&baseball[i][k].vorp>=baseball[i][k-1].vorp)
            vorp[i][j]=max(vorp[i][j-10],vorp[i-1][j-baseball[i][k].cost]+baseball[i][k].vorp);
        }

        }

    //递归实现结束
    cout<<"the result is "<<vorp[10][max_money];
    return 0;
}


 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值