首页 > 代码库 > 动态规划之签约棒球自由球员
动态规划之签约棒球自由球员
假设你是一支棒球大联盟球队的总经理。在赛季休季期间,你需要签入一些自由球员。球队老板给你的预算为X美元,你可以使用少于X美元来签入球员,但如果超支,球队老板就会解雇你。
你正在考虑在N个不同位置签入球员,在每个位置上,有P个该位置的自由球员供你选择。由于你不希望任何位置过于臃肿,因此每个位置最多签入一名球员(如果在某个特定位置上你没有签入任何球员,则意味着计划继续使用现有球员)。
为了确定一名球员的价值,你决定使用一种称为“VORP”,或“球员替换价值”的统计评价指标。球员的VORP值越高,其价值越高。但VORP值高的球员签约费用并不一定比VORP值低的球员高,因为还有球员价值之外的因素影响签约费用。
对于每个可选择的自由球员,你知道他的三方面信息:
1.他打哪个位置。2.他的签约费用。3.他的VORP。
设计一个球员选择算法,是的总签约费用不超过X美元,而球员的总VORP最大。你可以假定每位球员的签约费用是10万美元的整数倍。算法应输出签约球员的总VORP值,总签约费用,以及球员名单。分析算法的时间和空间复杂度。
思考与分析:这明显是一个改进的背包问题。不超过X美元,相当于背包的总容量。总VORP最大,相当于背包的总价值。每位球员的签约费用,相当于每件物品的重量。现在我们要给出在签约费用不超过X美元的前提下使总价值最大的球员选择方案。以0-1背包为背景的动态规划算法,我们可以给其改进一下,这里每个位置(相当于每件物品)有P个球员。那么我们要多加一个循环用于求在找到最大价值方案的前提下还要先找出P个球员之中的价值最大的那个。那么我们现在可以刻画出递归式。
递归式为:
代码如下:(本代码注释部分和背包相关问题做了一个对比,详细的解释了和背包问题的相似性,如果对背包问题有疑问可以打开上面的链接)
#include <iostream> #include <time.h> using namespace std; #define n 10 struct Player {//球员结构体 int cost;//雇佣球员的花费 int vorp;//球员的价值 }; void FREE_AGENT_VORP(struct Player **p,int N,int P,int X) {//采用从底到顶的顺序来设置v[i][j]的值 int **v,**who,i; v=new int*[N+1]; for ( i=0;i<=N;i++) { v[i]=new int[X]; } who=new int*[N+1]; for ( i=0;i<=N;i++) { who[i]=new int[X]; } //二维数组v[i][j]代表位置i的不超过总费用j时的总价值(相当于背包的总价值) //二维数组who[i][j]代表选择位置i的总费用不超过j的球员 for (int x=0;x<=X;x+=10)//10=10万 {//首先放v[n][x] v[N][x]=-0x7fffffff; who[N][x]=0;//x小于v[n][x],所对应的值设为0,否则就为可以放置 for (int k=0;k<=P;k++) { if (p[N][k].cost<=x&&p[N][k].vorp>v[N][x]) { v[N][x]=p[N][k].vorp; who[N][x]=k; } } } //对剩下的N-1个位置进行放置。 for ( i=N-1;i>=1;i--) { for (int x=0;x<=X;x+=10)//x代表当前总费用(相当于当前总重量j) { v[i][x]=v[i+1][x]; who[i][x]=0; for (int k=0;k<=P;k++) {//注意k=0时是现有球员,k=0表示不用替换球员 //p[i][k].cost代表位置i的第k个球员的费用(相当于位置i的第k个物品重量) //p[i][k].vorp代表位置i的第k个球员的价值(相当于位置i的第k个物品价值) if (x-p[i][k].cost>=0&&v[i+1][x-p[i][k].cost]+p[i][k].vorp>v[i][x]) {//选择在总费用范围内的总价值最大的那个球员 v[i][x]=v[i+1][x-p[i][k].cost]+p[i][k].vorp; who[i][x]=k; } } } } cout<<"最大价值="<<v[1][X]<<endl; int amt=X;//借用一个变量保存总费用(相当于总重量) for ( i=1;i<=N;i++) { int k=who[i][amt];//位置i的费用为不超过amt费用的球员k if (k!=0)//k非0时,说明要签约位置i的第k个球员 { cout<<"第"<<i<<"个位置"<<"第"<<k<<"个人->"; amt-=p[i][k].cost;//签约了一个球员后,剩余的总费用。(相当于剩余的总重量) } } cout<<"The total money spent is"<<X-amt<<endl; } void main() { //srand( (unsigned)time( NULL ) ); struct Player **p; int N=10,P=8,X=300;//X代表总费用(背包总重量X); p=new Player*[N+1]; for (int i=0;i<=N;i++) { p[i]=new Player[P+1]; } for (i=0;i<=N;i++) { for (int j=0;j<=P;j++) { p[i][j].cost=10*(j+1);//球员的费用(相当于物品的重量,其中0号位置不使用) p[i][j].vorp=rand()%300;//球员的价值(相当于物品的价值,0号位置置为空) } } FREE_AGENT_VORP(p,N,P,X); }总结:此算法运行时间为O(NXP),存储容量为O(NX). 本问题类似背包问题,也可以说是背包问题的一个升级版,多了一重循环,但本质是一样的。