您的位置:首页 > 其它

算法设计与分析:第四章 4.4资源分配问题

2015-08-05 09:51 961 查看
/*
资源分配问题:
是考虑如何把有限的资源分配给
若干个工程问题。假设资源总数为 r,工程个数为
n,给每个工程投入的资源不同,所得的利润也不
同,要求把总数为 r 的资源分配给n个工程,以获
得最大利润的分配方案。

决策过程:
把资源r划分为m个相同的部分,每份资源为r/m,m为整数。假定利润函数为
Gi(x)=把x份资源分配给第i个工程得到的利润
G(m) = i从1到n 累加求和Gi(xi)
i从1到n 累加求和xi = m
牛逼:问题转化为把m份资源分配给n个工程,使得G(m)最大的问题
m份资源
首先,把各个工程按顺序编号,按下述方法进行划分:
第一阶段:分别把x=0,1,...,m份资源给第1份个工程,确定在第一个工程在各种不同份额的资源下,
能够得到最大的利润
第二阶段:分别把x=0,1,...,m份资源分配给第1,2个工程,确定第1个工程在各种不同份额的
资源分配下,这两个工程能够得到的最大利润和第二个工程的最优分配份额。
在第n个阶段,分别把x=0,1,2,...,m份资源分配给所有n个工程,确定能够得到的最大利润,
以及在此利润下,第n个工程的最优分配份额。

考虑到把m份资源全部投入给所有n个工程一定能够得到最大利润,因此必须在各个阶段中,
对不同的分配份额计算,得到最大利润,然后取其中的最大者,作为每个阶段能够取得的
的最大利润。再取每个阶段的最大利润中的最大者,以及在该最大利润下的分配方案,
即为整个资源分配的最优决策

思想:
前缀法

1设fi(x)表示把x份资源分配给前i个工程时,所得到的最大利润,
di(x)表示使得fi(x)最大时,分配给第i个工程的资源份额。
在第一阶段,只把x份资源分配给第一个工程,有:
{f1(x) = G1(x)
{d1(x) = x        0<=x<=m
第二阶段,只把x份资源分配给第一、第二两个工程,有:
{f2(x)=max{G2(z) + f1(x-z)}
{d2(x) = 使得f2(x)最大的z    ,0<=x<=m,0<=z<=x

非常重要
第i个阶段,把x份资源分配给前i个工程,有:
Gi(x)=把x分资源分配给第i工程的利润
{fi(x)=max{Gi(z) + fi-1(x-z)}
{di(x) = 使得fi(x)最大的z,0<=x<=m,0<=z<=x

令第i阶段最大利润为gi,则:本质上是遍历各种解决方案
gi = max{fi(1),...,fi(m)}
设qi是使得gi最大时,分配给前面i个工程的资源份额,则:
qi = 使得fi(x)最大的x,这里的qi是整体
di = 使的fi(x)最大的当前工程得到的资源个数
Gi(x) = 把x份资源分配给前i个工程得到的利润
fi(x) = 把x份资源分配给前i个工程得到的最大利润
optg = max{g1,g2,...,gn}
k = 使gi最大的i
optx = 与最大的gi相对应的qi

在每个阶段中,把所得到的所有局部决策值fi(x),di(x),gi,qi保存起来。
最后,在第n阶段结束之后,令全局的最大利润为optg,则:
optg = max{g1,g2,...,gn}
在全局最大利润下,所分配工程项目的最大编号(即所分配工程项目的最大数目)为k,则:
k = 使gi最大的i
分配给前面k个工程的最优份额为:
optx = 与最大的gi相对应的qi[使得fi(x)最大的x]

分配给第k个工程的最优份额为:
optqk = dk(optx)[k是最大的i,optx全局的分配量]
分配给其余k-1个工程的剩余的最优份额为:
optx = optx - dk(optx)
由此回溯,得到分配给前面各个工程的最优份额的递推关系式:
{optqi=di(optx)
{optx=optx-optqi,i = k,k-1,...,1

输入:
3(工程数) 8(资源数),下面3行,每行9列
0 4 26 40 45 50 52 52 53
0 5 15 40 60 70 73 74 75
0 5 15 40 80 90 95 98 100
输出:
140
0 4 4 

x		0	1	2	3	4	5	6	7	8
G1(x)	0	4	26	40	45	50	52	52	53
G2(x)	0	5	15	40	60	70	73	74	75
G3(x)	0	5	15	40	80	90	95	98	100

第一步:求各个阶段不同分配的份额时在此利润下的分配额。
第一阶段,只把资源的份额分配给第一个工程:
x		0	1	2	3	4	5	6	7	8
f1(x)	0	4	26	40	45	50	52	52	53
d1(x)	0	1	2	3	4	5	6	7	8

g1 = 53 = max{f1(1),f1(2),...,f1(8)}
q1 = 8

第二阶段,只把资源分配给第1、2个工程
x = 1时,f2(1) = max(G2(0) + f1(1),G2(1) + f1(0)) = max(0 + 4,5 + 0) = 5  
x = 2时, f2(2) = max(G2(0) + f1(2),G2(1) + f1(1) ,G2(2) + f1(0))
			   = max(0 + 26,5 + 4,15+0) = 26
累次计算x=3,4...,8时的f2(x)以及d2(x)的值,有:
x		0	1	2	3	4	5	6	7	8
f2(x)	0	5	26	40	60	70	86	100	110
d2(x)	0	1	0	0	4	5	4	4	5

g2 = 110 = max{f2(1),f2(2),...,f2(8)}
q2 = 使g2取得最大的资源分配总数 = 8

同样计算f3(x)以及d3(x)的值有:
x		0	1	2	3	4	5	6	7	8
f3(x)	0	5	26	40	80	90	106	120	140
d3(x)	0	1	0	0	4	5	4	4	4

g3 = 140
q3 = 8

optg = max{g1,g2,g3} = g3 = 140
optg = 140,optx = 8,k = 3

{optqx = dk(optx)
{optx = optx - optqx
optq3 = d3(optx) =d3(8) = 4,optx = optx  - optq3 = 8 - 4 = 4
optq2 = d2(optx) =d2(4) = 4,optx = optx - optq2 = 4- 4 = 0
optq2 = d2(optx) =d1(0) = 0

计算各个工程的最优分配额度
f2(4) = 60

下面求各个阶段的最大利润,以及在此利润下的分配份额
gi=max{fi(1),...,fi(m)}
qi=使得fi(x)最大的x

算法流程:
1计算fi,di。fi(x) = max{Gi(z) + fi-1(x-z)},di(x) = 使fi(x)最大的z,计算方法采取递推方法
2计算gi,qi。gi = max{fi(1),fi(2),...,fi(n)}:对于前i个工程,分配各个资源数下的利润最大值,qi = 使gi最大的x
3计算optg,optq,k。optg = max{g1,g2,...,gn},k=使得全局利润最大的最大工程编号,optq = 使得optx最大的gi对应的qi
4计算optqx。optqx = dk(optx),optx = optx - optqx,直到所有工程计算完毕
*/

/*
关键:
1 令第i阶段最大利润为gi,则:本质上是遍历各种解决方案
gi = max{fi(1),...,fi(m)}
设qi是使得gi最大时,分配给前面i个工程的资源份额,则:
qi = 使得fi(x)最大的x,这里的qi是整体
di = 使的fi(x)最大的当前工程得到的资源个数
Gi(x) = 把x份资源分配给前i个工程得到的利润
fi(x) = 把x份资源分配给前i个工程得到的最大利润
optg = max{g1,g2,...,gn}
k = 使gi最大的i
optx = 与最大的gi相对应的qi

2 
1)计算fi,di。fi(x) = max{Gi(z) + fi-1(x-z)},di(x) = 使fi(x)最大的z,计算方法采取递推方法
2)计算gi,qi。gi = max{fi(1),fi(2),...,fi(n)}:对于前i个工程,分配各个资源数下的利润最大值,qi = 使gi最大的x
3)计算optg,optq,k。optg = max{g1,g2,...,gn},k=使得全局利润最大的最大工程编号,optq = 使得optx最大的gi对应的qi
4)计算optqx。optqk = dk(optx),optx = optx - optqi,直到所有工程计算完毕
*/

#include <iostream>
//#include <string>
//#include <fstream>
//#include <vector>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

using namespace std;
const int MAXSIZE = 100;

int g_iMatrix[4][9] = 
{
	{0,0,0,0,0,0,0,0,0},
	{0,4,26,40,45,50,52,52,53},
	{0,5,15,40,60,70,73,74,75},
	{0,5,15,40,80,90,95,98,100}
};
int g_f[MAXSIZE][MAXSIZE];//g_f[i][x]:表示将x个资源分配给钱前x个工程的最大利润
int g_d[MAXSIZE][MAXSIZE];//g_d[i][x]:表示使得g_f[i][x]最大的z
int g_g[MAXSIZE];		  //计算分配给前i个工程的利润最大值,g[i] = max{fi(1),fi(2),...,fi(n)}
int g_q[MAXSIZE];		  //g_q[i] = 使得g_g[i]最大的前i个工程的总共资源数
int g_optx;               //全局最大利润值
int g_optq;				  //全局最大利润下的所分配的资源总数
int g_k;				  //全局最大利润下的最大工程编号
int g_optqArr[MAXSIZE];   //g_optqArr[i]:存储第i个工程分配的资源个数

/*n:表示工程数,m:表示资源数*/
int allocate(int n,int m)
{
	//初始时:设置利润最小
	memset(g_optqArr,-1,sizeof(g_optqArr));
	memset(g_q,-1,sizeof(g_q));
	memset(g_g,-1,sizeof(g_g));
	memset(g_f,-1,sizeof(g_f));

	//动态规划数组赋初始值
	for(int j = 0 ; j <= m ; j++)
	{
		//初始,f1(x) = a[1[j],资源数,等于原来个数
		g_f[1][j] = g_iMatrix[1][j];
		g_d[1][j] = j;
	}

	//计算g1
	g_g[1] = g_f[1][1];
	g_q[1] = 1;
	for(int x = 2 ; x <= m ; x++)
	{
		if(g_g[1] < g_f[1][x])
		{
			g_g[1] = g_f[1][x];
			g_q[1] = x;
		}
	}

	//自底向上求各阶段,外层迭代
	for(int i = 2 ; i <= n ; i++)
	{
		//fi(x) = max(gi(z) + fi-1(x-z)),x属于[0,n],z属于[0,x]
		for(int x = 0 ; x <= m ; x++)
		{
			for(int z = 0 ; z <= x ; z++)
			{
				int iResult = g_iMatrix[i][z] + g_f[i-1][x-z];
				if(g_f[i][x] < iResult)
				{
					g_f[i][x] = iResult;
					//更新当前工程最大利润下的份额
					g_d[i][x] = z;
				}
			}
			//更新前i个工程,依次分配1,2,...,n个资源的利润最大值
			if(g_g[i] < g_f[i][x])
			{
				g_g[i] = g_f[i][x];
				g_q[i] = x;
			}
		}
	}

	//计算全局最大利润
	g_optx = g_g[1]; 
	g_optq = g_q[1];//g_q计算错误
	g_k = 1;
	for(int i = 2 ; i <= n ; i++)
	{
		if(g_optx < g_g[i])
		{
			g_optx = g_g[i];
			g_optq = g_q[i];
			g_k = i;
		}
	}

	//计算资源分配方案,optqi = dk(optx),optx = optx - optqi
	for(int i = n ; i >= 1 ; i--)
	{
		g_optqArr[i] = g_d[i][g_optq];
		g_optq -= g_optqArr[i];
	}
	return g_optx;
}

/*打印结果:全局最大利润,和资源分配方案*/
void printResult(int n)
{
	cout << g_optx << endl;
	for(int i = 1 ; i <= n ; i++)
	{
		if(i != 1)
		{
			cout << " " << g_optqArr[i];
		}
		else
		{
			cout << g_optqArr[i];
		}
	}
	cout << endl;
}

void process()
{
	int n;
	int m;//资源个数
	cin >> n >> m;
	{
		allocate(n,m);
		printResult(n);
	}
}

int main(int argc,char* argv[])
{
	process();
	getchar();
	system("pause");
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: