算法——动态规划之资源分配问题及其优化
2018-03-18 21:03
441 查看
上一篇文章写了动态规划求解0-1背包问题,这里做一道资源分配问题强化理解,顺便分析一下动态规划算法的优化问题。
问题描述:某厂根据计划安排,拟将n台相同的设备分配给m个车间,各车间获得这种设备后,可以为国家提供盈利Ci j(i台设备提供给j号车间将得到的利润,1≤i≤n,1≤j≤m) 。问如何分配,才使国家得到最大的盈利?
分析递推公式:
初始化:p[i][j]=0
然后分析一下,前i台设备分配给j个车间,考虑当前第j个车间的情况,当前车间可能分配0个设备、1个设备、2个设备、…、n个设备,这其中得到最大利润的方案即为最优方案,故有下面公式
p[i][j]=max{p[i][j],p[k][j-1]+c[i-k][j]} 其中0<=k<=i,1<=i<=n,1<=j<=m
代码如下:
优化一:
如果你在一个实例中尝试一下自己画表,你会发现,这道公式是按列计算数值的。
举个例子,2台设备分配给2个车间的盈利表(c[i][j])如图所示
初始化最大盈利表
根据公式填表(p[i][j]=max{p[i][j],p[k][j-1]+c[i-k][j]} )
p[1][1]=max{p[1][1],p[k][0]+c[1-k][1]},0<=k<=1
p[1][1]=max{p[1][1],p[0][0]+c[1][1],p[1][0]+c[0][1]}=max{0,189,0}=189
用于计算的有下面4个数字
这样看或许还不够明确,我们来算一下p[2][2]
p[2][2]=max{p[2][2],p[k][1]+c[2-k][2]},0<=k<=2
p[2][2]=max{p[2][2],p[0][1]+c[2][2],p[1][1]+c[1][2],p[2][1]+c[0][2]}
用于计算的有下面几个数字
问题浮出水面==>这条递推公式是按照列遍历的!!学过计算机组成原理的朋友可能已经知道了,没错,就是cache的问题。
改变一下存储方式即可让遍历按照行进行!
p[i][j]=max{p[i][j],p[i-1][k]+c[i][j-k]} 其中0<=k<=j,1<=i<=m,1<=j<=n
解释一下这条新公式:其实思想没改变,就是将i、j互换,这里i代表车间数,j代表设备数,公式表示前i个车间瓜分j台设备,考虑当前第i个车间的情况,当前车间可能分配0个设备、1个设备、2个设备、…、n个设备,这其中得到最大利润的方案即为最优方案。
注意c[i][j]表示与题干不同:它表示j台设备提供给i号车间将得到的利润,1≤i≤m,1≤j≤n
优化二:
上面优化后的公式是按照行遍历的,如果你尝试自己手动画图,会发现每次求解只需要用到两行
p[2][2]=max{p[2][2],p[1][k]+c[2][2-k]},0<=k<=2
p[2][2]=max{p[2][2],p[1][0]+c[2][2],p[1][1]+c[2][1],p[1][2]+c[2][0]}
c表只用于生成p表,用完就没有作用了,如果我们在生成c表一行的同时生成p表,便只需要一个一维数组c[n+1]存储c表和一个c[2*(n+1)]的二维数组存储p表,空间复杂度下降。
p表能否优化成一维数组呢?
答案是可以的,因为求p表第i行j列数据时只需要用到c表i行和p表i-1行的前j个数据,我们只需要从后往前遍历,便不会影响到其它数据的计算
优化后代码如下:
思考:p只是一个一维数组,我们只能通过它得知最大利润,如何得知分配的方案呢?
如果c和p还是二维数组的时候,其实可以不用分配表application,直接算出分配方案,但现在c和p已经优化为一维数组了,没有application我们无法得知分配方案。
那么application表只能是一个二维数组吗?
有的博主是这样做的:通过结构体存储,将application表中数值为0的部分省去。结构体内定义了3个int型数据,这种方法比较适合在0较多的application表中用,否则反而可能增加空间负担,得不偿失!请慎用!
想到结构体就想到了链表啦,如果像下图这样把每个地方的0压缩,或许可以减少一点空间负担,而且,链表不要求连续的空间
如图,把一行变成4个链表块,0的个数保存在链表块里。
问题描述:某厂根据计划安排,拟将n台相同的设备分配给m个车间,各车间获得这种设备后,可以为国家提供盈利Ci j(i台设备提供给j号车间将得到的利润,1≤i≤n,1≤j≤m) 。问如何分配,才使国家得到最大的盈利?
分析递推公式:
初始化:p[i][j]=0
然后分析一下,前i台设备分配给j个车间,考虑当前第j个车间的情况,当前车间可能分配0个设备、1个设备、2个设备、…、n个设备,这其中得到最大利润的方案即为最优方案,故有下面公式
p[i][j]=max{p[i][j],p[k][j-1]+c[i-k][j]} 其中0<=k<=i,1<=i<=n,1<=j<=m
代码如下:
int i, j, k; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) for (k = 0; k <= i; k++)//i代表了设备数目 if ((p[k][j - 1] + c[i - k][j]) > p[i][j]) { p[i][j] = p[k][j - 1] + c[i - k][j]; f[i][j] = i - k;//用于当前计算的车间的设备数 }
优化一:
如果你在一个实例中尝试一下自己画表,你会发现,这道公式是按列计算数值的。
举个例子,2台设备分配给2个车间的盈利表(c[i][j])如图所示
初始化最大盈利表
根据公式填表(p[i][j]=max{p[i][j],p[k][j-1]+c[i-k][j]} )
p[1][1]=max{p[1][1],p[k][0]+c[1-k][1]},0<=k<=1
p[1][1]=max{p[1][1],p[0][0]+c[1][1],p[1][0]+c[0][1]}=max{0,189,0}=189
用于计算的有下面4个数字
这样看或许还不够明确,我们来算一下p[2][2]
p[2][2]=max{p[2][2],p[k][1]+c[2-k][2]},0<=k<=2
p[2][2]=max{p[2][2],p[0][1]+c[2][2],p[1][1]+c[1][2],p[2][1]+c[0][2]}
用于计算的有下面几个数字
问题浮出水面==>这条递推公式是按照列遍历的!!学过计算机组成原理的朋友可能已经知道了,没错,就是cache的问题。
改变一下存储方式即可让遍历按照行进行!
p[i][j]=max{p[i][j],p[i-1][k]+c[i][j-k]} 其中0<=k<=j,1<=i<=m,1<=j<=n
解释一下这条新公式:其实思想没改变,就是将i、j互换,这里i代表车间数,j代表设备数,公式表示前i个车间瓜分j台设备,考虑当前第i个车间的情况,当前车间可能分配0个设备、1个设备、2个设备、…、n个设备,这其中得到最大利润的方案即为最优方案。
注意c[i][j]表示与题干不同:它表示j台设备提供给i号车间将得到的利润,1≤i≤m,1≤j≤n
优化二:
上面优化后的公式是按照行遍历的,如果你尝试自己手动画图,会发现每次求解只需要用到两行
p[2][2]=max{p[2][2],p[1][k]+c[2][2-k]},0<=k<=2
p[2][2]=max{p[2][2],p[1][0]+c[2][2],p[1][1]+c[2][1],p[1][2]+c[2][0]}
c表只用于生成p表,用完就没有作用了,如果我们在生成c表一行的同时生成p表,便只需要一个一维数组c[n+1]存储c表和一个c[2*(n+1)]的二维数组存储p表,空间复杂度下降。
p表能否优化成一维数组呢?
答案是可以的,因为求p表第i行j列数据时只需要用到c表i行和p表i-1行的前j个数据,我们只需要从后往前遍历,便不会影响到其它数据的计算
优化后代码如下:
void Dynamic_Optimization(int *cc, int *pp) { int i, j, k, u; //最开始最大利润表是0 for(i=0;i<=m;i++) { pp[i]=0; } cc[0]=0; for (i = 1; i <= m; i++)//m车间数 { for (j = 1; j <= n; j++) { //初始化一列利润表cc cc[j] = cc[j - 1] + rand() % 1000 + 1; } for (u = n; u >= 1; u--)//从后往前遍历 { int max = 0; for (k = u; k >= 0; k--) { if (pp[k] + cc[u - k] > max) { max = pp[k] + cc[u - k]; pp[u] = max; } } } } }
思考:p只是一个一维数组,我们只能通过它得知最大利润,如何得知分配的方案呢?
如果c和p还是二维数组的时候,其实可以不用分配表application,直接算出分配方案,但现在c和p已经优化为一维数组了,没有application我们无法得知分配方案。
那么application表只能是一个二维数组吗?
有的博主是这样做的:通过结构体存储,将application表中数值为0的部分省去。结构体内定义了3个int型数据,这种方法比较适合在0较多的application表中用,否则反而可能增加空间负担,得不偿失!请慎用!
结构体定义如下: Struct path{ Int shebei; Int chejian; Int num; }P[10000];
想到结构体就想到了链表啦,如果像下图这样把每个地方的0压缩,或许可以减少一点空间负担,而且,链表不要求连续的空间
如图,把一行变成4个链表块,0的个数保存在链表块里。
相关文章推荐
- 动态规划算法之资源分配问题及其空间优化方案
- 马踏棋盘问题(骑士周游问题)及其优化算法java实现
- 算法讲解之Dynamic Programing —— 背包DP [资源分配问题]
- 网络分析优化旅行商问题TSP算法资源
- 单源最短路径问题(dijkstra算法 及其 优化算法(优先队列实现))
- hdu 1874 最短路问题 地杰斯特拉算法及其heap优化
- 资源分配问题(动态规划)
- 动态规划求解资源最优分配问题
- java 数组中两数之差的最大值 蛮力算法 动态规划及其优化
- Josephus问题及其推广 分析和算法优化
- 多段资源分配问题(动态规划)
- 【Algorithm】一般约束优化问题——PHR算法及其Matlab实现
- 动态规划 - 0-1背包问题的算法优化
- 算法导论16.2-2--动态规划(0-1背包问题)
- 斐波那契数列算法优化问题
- [算法导论]练习16.1-4 活动教室分配(区间着色问题)
- 算法面试---01背包问题---动态规划
- 从最大子段和问题看算法的优化问题
- JAVA代码—算法基础:数塔问题(动态规划)
- 最短路的几种算法及其优化(模板)