08下半年软设一道关于动态归划的算法题

当时考试的时候没有弄明白,费了一天的功夫,终于解理了动态归划,过程及我的理解写下来。
一道关于动态归划的算法题:
试题四(共15分)
阅读下列说明,回答问题
1至问题3
【说某明餐】厅供应各种标准的营养套餐。假,设将菜解单答上填共入有答题纸的对应栏内。
n项食物m1,m2,…,mn食物,每项mi的营养价值为vi,价格为pi,其中i=1,2,…,n人常需要一个算法来求解总不超过,套餐中每项食物至多出现一次。客人常需要一个算法来求解总低格不超过M的营养最大的套餐。
伪代码中的主要变量说明如下:
n: 总的食物项数;
v: 营养价值数组,下标从1到n,对应第1到第n项食物的营养价值;
p: 价格数组,下标从1到n,对应第1到第n项食物的价格;
M:总价格标准,即套餐的价格不超过M;
x: 解向量(数组),下标从1到n,其元素值为0或1,其中元素值为0表示对应的食物不出现在套餐中,元素值为1表示对应的食物出现在套餐中;
nv:n+1行M+1列的二维数组,其中行和列的下标均从0开始,nv[i][j]表示由前i项食物组合且价格不超过 j 的套餐的最大营养价值。问题最终要求的套餐的最大营养价值为nv[n][M]。
伪代码如下:
MaxNutrientValue(n, v, p, M, x)
1 for i = 0 to n
2 nv[i][0] = 0
3 for j = 1 to M
4 nv[0][j] = 0
5 for i = 1 to n
6 for j = 1 to M
7 if j < p[i] //若食物mi不能加入到套餐中8 nv[i][j] = nv[i - 1][j]
9 else if(1)
10 nv[i][j] = nv[i - 1][j]
11 else
12 nv[i][j] = nv[i - 1][j – p[i]] + v[i]
13 j = M
14 for i = n downto 1
15 if(2)
16 x[i] = 0
17 else
18 x[i] = 1
19 (3)
20 return x and nv[n][M]



完整java代码如下:
class Max{
int max (int n, int v[], int p[], int M, int x[])
{
int i, j;
int nv[][] = new int[n+1][M+1];
for (i = 0; i <= n; i++)
nv[i][0] = 0;
for (j = 0; j <= M; j++)
nv[0][j] = 0;
for (i = 1; i <= n; i++)
for (j = 1; j <= M; j++)
{
if (j < p[i]) //(1)
nv[i][j] = nv[i-1][j];
else if (nv[i-1][j] >= (nv[i-1][j-p[i]] + v[i])) //(2)
nv[i][j] = nv[i-1][j];
else
nv[i][j] = nv[i-1][j-p[i]] + v[i];
}
j = M;
for (i = n; i >=1; i--)
{
//if ( (nv[i-1][j-p[i]] + v[i]) < nv[i][j] || j<=0)
if(nv[i][j] == nv[i-1][j])
x[i] = 0;
else
{
x[i] = 1;
j = j - p[i];
}
}
return nv[n][M];
}
}

public class MaxValue {
public static void main(String[] args) {
int n = 5, M = 100;
//int nv[][] = new int[n+1][M+1];
int x[] = {0, 0, 0, 0, 0, 0};
int p[] = {0, 50, 30, 45, 25, 5};
int v[] = {0, 200, 180, 225, 200, 50};
Max m = new Max();
m.max(n, v, p, M, x);
System.out.println("应选取的食物为:");
for (int i = 1; i < 6; i++)
{
if (x[i] == 1)
System.out.println(i);
}
System.out.println("产生的最大营养价值为:" + m.max(n, v, p, M, x));
}
}
(1) 此处比较是为了确定位置的价格是否可以购买当前行标准的食物,如果钱不够买,那么就使用前一行数组对应当前列的值(花的钱一样多)作为最大的营养标准(你都买不起,还用考虑这类标准的食物吗?)。如果钱够了,可以买得起了,那么就得考虑是否要购买这类食物,买了会不会有利于组合出最大的营养价值出来,也就进入了下面的一组判断。
(2) 重要是这个判断,首先要理解的是以下几个式子的意思:
j-p[i]表示在当前的价格标准下,把当前食物加入套餐后还剩余的钱( j为当前价格标准,p[i]当前食物的价格)
nv[i - 1, j - p[i]] + v[i]是把当前价格标准的食物买入的情况下产生的营养价值,如果买入了当前价格标准的食物,那么会多产生v[i]的营养价值,剩余的钱为j - p[i],那点剩余的钱对应的最大营养价值为不包含当前价格标准的食物下价格为j - p[i]的最大营养价值,也就是前一行数组中第j - p[i]的值,比较这两个位置的值后,就可以确定是否需要包含当前价格标准的食物了。如果nv[i - 1, j]的值大,就不包含当前价格标准的食物,反之则包含当前价格标准的食物,最大营养价值为nv[i - 1, j - p[i]] + v[i]。
因为nv[i-1,j-p[i]]+v[i]很可能小于不加入食物i时的营养值,即nv[i-1,j]
这里如果没仔细想可能还不明白,为什么加了当前食物的营养值还会小于不加入的呢?因为要受到一个价格因素的影响,如果当前食物的价格很高,而营养值却不太高,而如果不加入这个食物,省下的钱可以买几个食物,这几个食物的营养值之和可能更大。nv[x,y]代表在x项食物中选择的价格小于y的营养值最高的套餐的营养值 .所以nv[i,j]的值就要从nv[i - 1, j-p[i]] + v[i] 和nv[i-1][j]里面选一个较大值.任何一个套餐的最高营养值都是这两个值中的最大值。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值