算法设计与分析:矩阵连乘和币值最大问题(C/C++/Java)

采用了动态规划来解决以下两个问题,其中矩阵连乘分别用了递归、动态规划,币值最大化问题用了递归、动态规划和备忘录方法。

Java:

矩阵连乘:

import java.util.Date;
import java.util.Scanner;

public class MatrixMultiplication {
    static int[][] s1 = null;
    static int[][] s2 = null;
    static int[][] s3 = null;
    static int[][] m1 = null;
    static int[][] m2 = null;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.print("请输入矩阵个数:");
        int n = sc.nextInt();
        int[] p = new int[n+1];
        initArray(n);
        System.out.print("输入矩阵维数:");
        for (int i = 0; i <= n; i++) {
            p[i] = sc.nextInt();
        }

        //快速测试样例
//        int[] p = new int[]{30, 35, 15, 5, 10, 20, 25, 50, 24, 36,48,50,25,19,27,74,89};
//        int n = p.length-1;

        //初始化数组
        initArray(n);

        matrixChain(p, m1);
        System.out.println("\n==============================不同划分的计算次数为:==============================");
        for (int i = 1; i <= n; i++) {
            for (int j = 2; j <= n; j++) {
                System.out.printf("%10d\t", m1[i][j]);
            }
            System.out.println();
        }

        fun("动态规划法", 1, n, p);
        fun("备忘录法", 2, n, p);
        fun("递归法", 3, n, p);
    }

    private static void initArray(int n) {
        s1 = new int[n+1][n+1];
        s2 = new int[n+1][n+1];
        s3 = new int[n+1][n+1];
        m1 = new int[n+1][n+1];
        m2 = new int[n+1][n+1];
    }

    private static void matrixChain(int[] p, int[][] m) {
        int n = p.length - 1;
        for (int i = 1; i <= n; i++) {
            m[i][i] = 0;
        }

        for (int i = 2; i <= n; i++) {
            for (int j = 1; j <= n - i + 1; j++) {
                int k = j + i - 1;
                m[j][k] = m[j + 1][k] + p[j - 1] * p[j] * p[k];
                s1[j][k] = j;
                for (int q = j + 1; q < k; q++) {
                    int t = m[j][q] + m[q + 1][k] + p[j - 1] * p[q] * p[k];
                    if (t < m[j][k]) {
                        m[j][k] = t;
                        s1[j][k] = q;
                    }
                }
            }
        }
    }

    private static int lookupChain(int i, int j, int[] p) {
        if (m2[i][j] > 0)
            return m2[i][j];
        if (i == j)
            return 0;
        int u = lookupChain(i + 1, j, p) + p[i - 1] * p[i] * p[j];
        s2[i][j] = i;
        for (int k = i + 1; k < j; k++) {
            int t = lookupChain(i, k, p) + lookupChain(k + 1, j, p) + p[i - 1] * p[k] * p[j];
            if (t < u) {
                u = t;
                s2[i][j] = k;
            }
        }
        m2[i][j] = u;          //纪录最小次数
        return u;
    }

    private static int RecurMatrixChain1(int i, int j, int p[]) {
        if (i == j) return 0;
        int u = RecurMatrixChain1(i, i, p) + RecurMatrixChain1(i + 1, j, p) + p[i - 1] * p[i] * p[j];
        s3[i][j] = i;
        for (int k = i + 1; k < j; k++) {
            int t = RecurMatrixChain1(i, k, p) + RecurMatrixChain1(k + 1, j, p) + p[i - 1] * p[k] * p[j];
            if (t < u) {
                u = t;
                s3[i][j] = k;
            }
        }
        return u;
    }

    private static void traceback(int[][] s, int i, int j) {
        if (j == 0)
            return;
        if (i == j)
            System.out.print("A" + i);
        else {
            System.out.print("(");
            traceback(s, i, s[i][j]);
            traceback(s, s[i][j] + 1, j);
            System.out.print(")");
        }
    }

    static void  fun(String method, int which, int n, int[] p){
        System.out.println("=================================" + method + "=================================");
        System.out.print(method + "求解出最少计算次数为:");
        Date date1 = new Date();
        switch (which){
            case 1:
                matrixChain(p, m1);
                System.out.print(m1[1][n] + "\n矩阵划分为:");
                traceback(s1, 0, n);
                break;
            case 2:
                System.out.println(lookupChain(1, n, p));
                System.out.print("矩阵划分为:");
                traceback(s2, 0, n);
                break;
            case 3:
                System.out.println(RecurMatrixChain1(1, n, p));
                System.out.print("矩阵划分为:");
                traceback(s3, 0, n);
                break;
        }
        Date date2 = new Date();

        System.out.println("\n耗费时间为:" + (date2.getTime()-date1.getTime()) + "毫秒");
    }
}

币值最大问题:

import java.util.Iterator;
import java.util.Scanner;
import java.util.TreeSet;

public class MaxMoney {

    static int[] a = null;
    static int[] c = null;
    static int[] f = null;
    static int[] arr = null;

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        System.out.print("请输入硬币的个数:");
        int n = s.nextInt();

        initArray(n);
        System.out.println("输每个硬币面额:");
        for (int i = 1; i <= n; i++) {
            c[i] = s.nextInt();
        }

        System.out.print("递归法求得结果为:" + fun1(n - 1));

        System.out.print("\n备忘录法求得结果为:" + fun2(n - 1));

        System.out.print("\n动态规划法求得结果为:");
        coinRow(n - 1);
        System.out.println(f[n - 1]);

        int count = 0;
        for (int i = n; i >= 1 ; i--) {
            if (f[i] == f[i - 1])
            {
                arr[count++] = c[--i];
            } else {
                arr[count++] = c[i--];
            }
        }
        System.out.println("拿的面额分别为");
        for (int i = n; i >= 0; i--) {
            if(arr[i] > 0)
                System.out.print(arr[i] + "\t");
        }
    }

    private static void initArray(int n) {
        a = new int[n+1];
        c = new int[n+1];
        f = new int[n+1];
        arr = new int[n+1];
    }

    //普通递归求
    static int fun1(int n) {
        if (n == 0)
            return c[0];
        if (n == 1)
            return Math.max(c[0], c[1]);
        else
            return Math.max(c[n] + fun1(n - 2), fun1(n - 1));
    }

    //备忘录
    static int fun2(int n) {
        if (n == 0)
            return c[0];
        if (n == 1)
            return Math.max(c[0], c[1]);
        else if (a[n] != 0)
            return a[n];
        return a[n] = Math.max(c[n] + fun2(n - 2), fun2(n - 1));
    }

    //动态规划法求
    static void coinRow(int n) {
        f[0] = 0;
        f[1] = c[1];

        for (int i = 2; i <= n; i++) {
            f[i] = Math.max(c[i] + f[i-2], f[i-1]);
        }
    }
}

C/C++:

矩阵连乘

#include <iostream>
#include <climits>
#include <cstdio>
using namespace std;

void MatrixChain_Dynamic(int n, int *size, int **m, int **s)
{
    for (int i = 1; i <= n; i++)
        m[i][i] = 0;             // l = 1
    for (int l = 2; l <= n; l++) // l is the chain length, 自底向上!
    {
        int j;
        for (int i = 1; i <= n + 1 - l; i++)
        {
            j = l + i - 1;
            m[i][j] = m[i][i] + m[i + 1][j] + size[i - 1] * size[i] * size[j]; // k = i
            s[i][j] = i;                                                       // k = i
            int tmp;
            for (int k = i + 1; k < j; k++)
            {
                tmp = m[i][k] + m[k + 1][j] + size[i - 1] * size[k] * size[j];
                if (tmp < m[i][j])
                {
                    m[i][j] = tmp;
                    s[i][j] = k;
                }
            }
        }
    }
}

int MatrixChain_Recursive(int i, int j, int *size, int **s)
{
    if (i == j)
        return 0;
    int result = INT_MAX;
    int tmp;
    for (int k = i; k < j; k++)
    {
        tmp = MatrixChain_Recursive(i, k, size, s) + MatrixChain_Recursive(k + 1, j, size, s) + size[i - 1] * size[k] * size[j];
        if (tmp < result)
        {
            result = tmp;
            s[i][j] = k;
        }
    }
    return result;
}

int MatrixChain_LookUp(int i, int j, int *size, int **m, int **s)
{
    if (m[i][j] > 0)
        return m[i][j];
    if (i == j)
        return 0;
    int result = INT_MAX;
    int tmp;
    for (int k = i; k < j; k++)
    {
        tmp = MatrixChain_LookUp(i, k, size, m, s) + MatrixChain_LookUp(k + 1, j, size, m, s) + size[i - 1] * size[k] * size[j];
        if (tmp < result)
        {
            result = tmp;
            s[i][j] = k;
        }
    }
    m[i][j] = result;
    return result;
}

int MemorizedMatrixChain(int i, int j, int n, int *size, int **m, int **s)
{
    for (int p = 1; p <= n; p++)
        for (int q = 1; q <= n; q++)
            m[p][q] = 0;
    return MatrixChain_LookUp(i, j, size, m, s);
}

void ConstructSolution(int i, int j, int **s)
{
    if (i == j)
        cout << 'A' << i;
    else
    {
        cout << '(';
        ConstructSolution(i, s[i][j], s);
        ConstructSolution(s[i][j] + 1, j, s);
        cout << ')';
    }
}

int main()
{
    int size[] = {30, 35, 15, 5, 10, 20, 25};
    int n = sizeof(size) / sizeof(*size) - 1;
    int **m = new int *[n + 1];
    int **s = new int *[n + 1];
    for (int i = 1; i <= n; i++)
    {
        m[i] = new int[n + 1];
        s[i] = new int[n + 1];
    }
    MatrixChain_Dynamic(n, size, m, s);
    printf("Dynamic Programming:\n ");
    cout << m[1][n] << endl;
    cout << m[2][5] << endl;

    printf("Divide-Conquer:\n");
    cout << MatrixChain_Recursive(1, n, size, s) << endl;
    cout << MatrixChain_Recursive(2, 5, size, s) << endl;

    printf("备忘录法: \n");
    cout << MemorizedMatrixChain(1, n, n, size, m, s) << endl;
    cout << MemorizedMatrixChain(2, 5, n, size, m, s) << endl;

    ConstructSolution(1, n, s);
    cout << endl;
    for (int i = 1; i <= n; i++)
    {
        delete[] m[i];
        delete[] s[i];
    }
    delete[] m;
    delete[] s;

    return 0;
}

币值最大问题:

#include "stdio.h"
#include"math.h"

#define max(x,y)  (x>y)?x:y
#define MAX 20
int c[MAX];
int f[MAX];
long a[MAX]={0};
//动态规划
int coinmax(int n)
{
    c[0] = 0;//初始化c[0]及f[0]
    f[0] = 0;
    f[1] = c[1];

    for (int i = 2; i <= n; i++)
    {
        f[i] = max(c[i] + f[i - 2], f[i - 1]);
            //获取最大币值
    }
		return f[n];

	}
//递归
int coinmax1(int n)
{
    c[0]=0;
    f[0]=0;
    f[1] = c[1];
    if(n<=1)
        return c[n];
    else
        return max(c[n]+coinmax(n-2),coinmax(n-1));
	}
//备忘录
int coinmax2(int n)
{
    c[0]=0;
    f[0]=0;
    f[1] = c[1];
    if (n == 0)
            return c[0];
        if (n == 1)
            return max(c[0], c[1]);
        else if (a[n] != 0)
            return a[n];
        return a[n] = max(c[n] + coinmax2(n - 2), coinmax2(n - 1));

	}
int main()
{
    int n;
    printf("请输入有多少个硬币:");
    scanf("%d", &n);
    printf("请分别输入每一张硬币的价值:");
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &c[i]);
    }
    int arr[MAX];//定义arr数组表示所选择的硬币
    int num = 0;
    printf("最大币值为(DP):%d\n", coinmax(n));
    printf("最大币值为(digui):%d\n", coinmax1(n));
    printf("最大币值为(beiwanglu):%d\n", coinmax2(n));
    for (int i = n; i >= 1; i--)
    {
        if (f[i] == f[i - 1])//选择了第i-1个,然后再将第i-1个放进arr数组
        {
            arr[num++] = c[--i];
        }
        else{
            arr[num++] = c[i--];//没有选择第i-1个则将他本身先放入数组,
            }
		}
		printf("所选各个币值为:");
		for (int i = 0; i<num; i++)
			printf("%d ", arr[i]);

	}

qq:1351006594

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aaron_Liu0730

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值