多段资源分配问题
题目内容
设有资源n(n为整数),分配给m个项目, gi(x) 为第i个项目分得资源 x 所得到的利润,求总利润最大的资源分配方案, 也就是解下列问题:
max z=g1(x1)+g2(x2)+...+gm(xm)
x1+x2+...+xm=n , 0≤x1≤n且xi为整数, i=1,2,3,...,m
方法一:暴力法 orz
思路
简单来说就是把每一种情况试一遍,时间复杂度嘛。。。不存在的( O(2N) )
采用多重循环或者递归,时间复杂度太高,这里不讨论。
方法二:动态规划
思路
假设 fi(x) 为将资源x分给前i个项目所获得的最大利润,得出状态转移方程:
{f1(x)=gi(x) 0≤x≤nfi(x)=max(gi(x)+fi−1(n−x)) 0≤x≤n
假设:
const int RESOURCE = 4; //有4个资源
const int CASE_NUM = 3; //3个项目
每个项目对应额度的利率:
项目\投资额度 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
1 | 0.23 | 0.35 | 0.36 | 0.49 |
2 | 0.22 | 0.36 | 0.39 | 0.54 |
3 | 0.38 | 0.45 | 0.90 | 0.45 |
首先对1号竞争者进行资源分配
对1号分配的资源数量 | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
f1(x) | 0 | 0.23 | 0.7 | 1.08 | 1.96 |
那么2号资源和2号资源一起分配的情况:
设对1,2一共分配的资源数为S
2号项目分配资源数为M
S\M | 0 | 1 | 2 | 3 | 4 | fi(x) |
---|---|---|---|---|---|---|
1.. | # f1(1) | f1(1−1)+1∗0.22 | 0.23 | |||
2.. | f1(2) | f1(2−1)+1∗0.22 | # f1(2−2)+2∗0.36 | 0.72 | ||
3.. | f1(3) | f1(3−1)+1∗0.22 | f1(3−2)+2∗0.36 | # f1(3−3)+3∗0.39 | 1.17 | |
4.. | f1(4) | f1(4−1)+1∗0.22 | f1(4−2)+2∗0.36 | f1(4−3)+3∗0.39 | # f1(4−4)+4∗0.54 | 2.16 |
将1和2的状态合并:
对1号分和2号配的资源数量 | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
f2(x) | 0 | 0.23 | 0.72 | 1.17 | 2.16 |
同理, 计算 f3(x) 时, 使用上面方法计算
代码实现:
#include <iostream>
using namespace std;
const int RESOURCE = 4; //资源数量
const int CASE_NUM = 3; //项目数量
//各个项目对应投资量的收益率
const double RATE[CASE_NUM][RESOURCE+1] = {{0, 0.23, 0.35, 0.36, 0.49},
{0, 0.22, 0.36, 0.39, 0.54},
{0, 0.38, 0.45, 0.9, 0.45}};
//保存前i个项目的对于每个资源的最大收益的数组(可以用一维数组代替,这里为debug方便)
double array[100][100] = {0};
int main(){
//初始化第一个项目的各个投资数的最佳收益
for(int i = 0; i <= RESOURCE; i++){
array [0][i] = i*RATE[0][i];
}
int all = 0; //all为目前已经投资的资源数
for(int i = 1; i < CASE_NUM; i++){ //求每个项目的投资数
int y = 0; //第i - 1 项目要投资的资源
for(int j = 0; j <= RESOURCE; j++){ ////给前i个项目总共分配的资源,项目投资数 0~RESOURCE
double maxx = 0; //当前投资数下最大盈利
for(int k = 0; k <= j; k++){ //给第i个投资k个资源, k < = RESOURCE
double temp = array[i - 1][j - k] + k * RATE[i][k];
if(temp >= maxx){
maxx = temp;
y = j - k;
}
}
array[i][j] = maxx;
}
all += y;
printf("%d 号CASE投资 %d个\n", i-1, y);
}
printf("%d 号CASE投资 %d个\n", CASE_NUM - 1, RESOURCE - all);
//打印每个项目对于每个数量资源的最大收益的数组(可以省略不要,这里为debug方便)
for(int i = 0; i < CASE_NUM; i++){
for(int j = 0; j <= RESOURCE; j++){
printf("%lf ", array[i][j]);
}
printf("\n");
}
}