投资组合问题

动态规划合集:

1.矩阵链乘法
2.投资组合问题
3.完全背包问题
4.01背包问题
5.最长公共子序列

例题2——投资问题

描述

设 我们现在有m元钱,n项投资,函数表示将x元投入第i个项目所产生的效益,,问如何分配这m元钱,使得总的投资效益最高?

假设钱数的分配都是非负整数,分配给第i个项目的钱数是,那么该问题可以描述为:

实例

投资组合问题_第1张图片
实例

子问题的界定和计算顺序

子问题界定:我们正常的想法K个项目,可以看看投前1个项目时候的收益,投前2个项目的....一直到前5个项目(全部项目)的最大收益,而对于前k个项目的收益,这里还需要对投入的钱再进行细分,前一个项目的时候,投入x元的最大收益(x=1,2...m)。这里也就出现了两个参数K和x。

在矩阵链中,我们的两个参数i和j都是同一个含义,就是矩阵的位置下标。这里我们的k和x是代表着不同的含义。

如果令表示x万元投入到前k个项目中,我们可以获得的最大收益。首先,我们从X万元中,分配万元给第k个项目,那么剩下的万元,就给前个项目,而前的最佳分配方案已经计算过,那么我们也就得到了递推方程:
\begin{array} {l}{F_{k}(x)=\max _{0\le x_{k}<x}\left\{f_{k}\left(x_{k}\right)+F_{k-1}\left(x-x_{k}\right)\right\}, \quad k=2,3, \cdots, n} \\ {F_{1}(x)=f_{1}(x), \quad F_{k}(0)=0, \quad k=1,2, \cdots, n} \end{array}

投资组合问题_第2张图片
备忘录与标记函数

这个问题的初始化是即得到了的第一列。

根据递推公式:


依次类推,可以得到

在计算的时候,只会考虑 即与无关。依次类推计算。

代码实现

public class Investment {
    public static int[][] mem;
    public static int[][] tag;
    private static int compute_max_invest(int[][] invest,int n,int k) {
        // i 表示 前 i个 项目  i=0是第一个项目,已经初始化 所以从i=1开始
        for (int i = 1; i < k; i++) { // 1 2 3
            // j 来表示 分配j万元
            for (int j = 1; j < n; j++) { // 0 1 2 3 4 5
                // 当分配j万元时候 在各种组合中的求最大
                int max = Integer.MIN_VALUE;
                for (int l = 0; l <= j; l++) {
                    // F_k(x) = max{ f_k(x_k) + F_{k-1}(x-x_k) }
                    // temp = 第i个项目投入l万元 + 前i-1个项目投入j-l万元
                    int temp = invest[l][i]+mem[j-l][i-1];
                    if (temp >= max){
                        mem[j][i] = temp;
                        max = temp;
                        tag[j][i] = l;
                    }
                }
            }
        }
        return mem[n-1][k-1];
    }

    public static void trace_result(int res[],int k,int n){
        int total = n-1;
        // k 是项目数
        for (int i = k-1; i >= 0; i--) {
            int temp = tag[total][i];
            total -= temp;
            res[i] = temp;
        }
    }

    public static void main(String[] args) {
        // 输入是一个n*k的矩阵
        int invest[][] ={{0,0,0,0},{11,0,2,20},{12,5,10,21},{13,10,30,22},{14,15,32,23},{15,20,40,24}};
        int n = invest.length; // 行数  表示投入 n万元 n=6 实际上是 0 1 2 3 4 5
        int k = invest[0].length; // 列数  表示 共多少个项目
        mem = new int[n][k];
        tag = new int[n][k];
        System.out.println("输入数据为");
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < k; j++) {
                System.out.printf("%d ",invest[i][j]);
            }
            System.out.println();
        }
        // 初始化 将 第一个项目的资金 放入 备忘录。
        // 标记函数
        for (int i = 0; i < n; i++) {
            mem[i][0] = invest[i][0];
            tag[i][0] = i;
        }

        int result[] = new int[k];
        int max_invest = compute_max_invest(invest,n,k);
        System.out.printf("max_investion:%d\n",max_invest);
        System.out.println("备忘录如下:");
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < k; j++) {
                System.out.printf("%d ",mem[i][j]);
            }
            System.out.println();
        }
        System.out.println("追踪解如下:");
        trace_result(result,k,n);
        for (int i = 0; i < k; i++) {
            System.out.println(result[i]);
        }
    }
}

你可能感兴趣的:(投资组合问题)