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