投资组合问题

动态规划合集:

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

例题2——投资问题

描述

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

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

实例

16484271-5be8244c5b8c4c3b.png
实例

子问题的界定和计算顺序

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

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

如果令表示x万元投入到前k个项目中,我们可以获得的最大收益。首先,我们从X万元中,分配万元给第k个项目,那么剩下的万元,就给前个项目,而前的最佳分配方案已经计算过,那么我们也就得到了递推方程:

16484271-32c0d7c4ffc51ac3.png
备忘录与标记函数

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

根据递推公式:


依次类推,可以得到

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

代码实现

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]);
        }
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值