先写一个两个矩阵相乘的
#include "pch.h"
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
/*
3 3 2
1 2 3
4 5 6
7 8 9
2 3
6 1
0 2
*/
int n, m, q; // n*m m*q
//注意c一定要用引用
void muiltipy(const vector<vector<int>>& a,const vector<vector<int>>& b, vector<vector<int>>& c) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= q; j++) {
int t = 0;
for (int k = 1; k <= m; k++) {
t = t + a[i][k] * b[k][j];
}
c[i][j] = t;
}
}
}
void print(const vector<vector<int>>& c) {
cout << "结果为:" << endl;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= q; j++)
cout << c[i][j] << " ";
cout << endl;
}
}
int main()
{
//a:[n*m] b:[m*q]
cin >> n >> m >> q;
vector<vector<int>> a = vector<vector<int>>(n + 1, vector<int>(m + 1, 0));
vector<vector<int>> b = vector<vector<int>>(m + 1, vector<int>(q + 1, 0));
vector<vector<int>> c = vector<vector<int>>(n + 1, vector<int>(q + 1, 0));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j];
for (int i = 1; i <= m; i++)
for (int j = 1; j <= q; j++)
cin >> b[i][j];
muiltipy(a,b,c); //将a和b矩阵相乘, 放到c中
print(c);
return 0;
}
矩阵要求前提:相邻矩阵满足相乘条件
c++版
//矩阵连乘问题:
// 求A1...An连乘后 最小的相乘次数
#include<iostream>
#include<memory.h>
using namespace std;
#define inf 0x3f3f3f3f
#define max 100
// A1 A2 A3 A4 A5 A6
// 30*35 35*15 15*5 5*10 10*20 20*25
int p[] = {30,35,15,5,10,20,25}; //矩阵的维数
int m[max][max]; //m[i][j] 表示Ai...Aj的最小相乘次数
int s[max][max]; //存储断点k的位置
int k;
int n = 6; //矩阵个数
//将矩阵用断点k分开 【Ai...Ak】【A(k+1)...Aj】
/*
表达式为: m[i][j] = 0; (i = j);
m[i][k]+m[k+1][j]+p[i-1][k][j]; i < j
*/
//由2个矩阵相乘有最优解 可以得到3个矩阵的最优解 ...4个5个...n个
void partition(int i,int j){
if(i == j)
cout << "A" << i;
else{
cout << "(";
partition(i,s[i][j]);
partition(s[i][j]+1,j);
cout << ")";
}
}
void print(){
cout << "m[][]:" << endl;
for(int i = 1; i <= n ;i ++){
for(int j = 1;j <= n;j ++)
cout << m[i][j] << " ";
cout << endl;
}
cout << "s[][]:" << endl;
for(int i = 1; i <= n; i ++){
for(int j = 1;j <= n;j ++)
cout << s[i][j] << " ";
cout << endl;
}
cout << "最少相乘次数:" << m[1][n] << endl;
cout << "分割方案:";
}
//动态规划方法 自底向上
void dinamic(){
for(int r = 2; r <= n; r ++){
for(int i = 1; i <= n-r+1; i ++){
int j = i + r -1;
m[i][j] = inf;
for(int k = i; k < j; k ++){
int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
if(t < m[i][j]){
m[i][j] = t;
s[i][j] = k;
}
}
}
}
//r控制链长
/*
for(int r = 1; r <= n; r ++){
for(int i = 1; i <= n-r+1; i ++){
int j = i + r ;
m[i][j] = inf;
for(int k = i; k < j; k ++){
int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
if(t < m[i][j]){
m[i][j] = t;
s[i][j] = k;
}
}
}
}*/
print();
partition(1,n);
}
//递归方式 自顶向下
//函数意义: f(i,j) 返回A[i,j]的最少相乘次数
int digui(int i,int j){
if(m[i][j] > 0) return m[i][j]; //记忆化搜索
if(i == j)
return 0;
else{
m[i][j] = inf;
for(int k = i; k < j; k ++){
int t = digui(i,k) + digui(k+1,j) + p[i-1]*p[k]*p[j];
if(t < m[i][j]){
m[i][j] = t;
s[i][j] = k;
}
}
}
return m[i][j];
}
int main()
{
cout << endl << "动态规划解法:" << endl;
dinamic();
cout << endl << endl << "递归解法:" << endl;
memset(m,0,sizeof(m));
memset(s,0,sizeof(s));
digui(1,n);
print();
partition(1,n);
return 0;
}
以C++版的作分析:
动态规划:全局问题分解n个子问题 每个子问题由n个解但要找出最优的 并且各个子问题不独立
总体思想:先求出链长为2的结果 这个结果唯一 A1A2 A2A3 A3A4... An-1An 存储起来作为链长为3的条件(子问题的最优解),
这也是动态规划自底向上和由子问题的最优解构造全局问题的最优解的思想。
这里关于j解释一下: j是矩阵连乘的结尾范围 例如:A[1,4] 那么i是1 j是4 计算A1A2A3A4的最优次数 这里的断点插入到A4之前就行了 即(A1A2A3)(A4) 这时A1..A4的所有子问题的解已经求完 如果像我注释的j = i + r; 那么j每次都循环到最后
m[i][k]=(A1A2A3A4) m[k+1][j] 已经超出范围了 如果这时候m数组开辟空间不够 会产生数组越界的情况。
几个注意点:
1.m【】【】数组必须从1开始 因为涉及到i-1的寻址方式
2..m【】【】结果唯一,分解方式并不唯一
3.p[i-1]是行 p[i]是列 矩阵连乘需要一个行和两个列 这里的 p[i-1]*p[k]*p[j]就是将首位的行 断点的列 结尾的列相乘 加上所有分割就是当前子问题的一个解 但不是最优。
java
// p[] 矩阵的维数
// m[][] m[i][j] 表示[Ai..Aj]的最少相乘次数
// s[][] 断点位置
public class dongtai {
static int inf = 0x3f3f3f3f;
static int n = 6;
static int p[] = {30,35,15,5,10,20,25};
static int m[][] = new int[n+1][n+1];
static int s[][] = new int[n+1][n+1];
public static void println(){
System.out.println("m[][]: ");
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++)
System.out.print(m[i][j] +" ");
System.out.println();
}
System.out.println("s[][]: ");
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++)
System.out.print(s[i][j] +" ");
System.out.println();
}
}
public static void partation(int i, int j){
if(i == j){
System.out.print("A" + i);
}else {
System.out.print("(");
partation(i, s[i][j]);
partation(s[i][j]+1,j);
System.out.print(")");
}
}
public static void main(String args[]){
//链长
for(int r = 2; r <= n; r ++){
for(int i = 1; i <= n-r+1 ;i ++){
int j = i + r - 1;
m[i][j] = inf;
for(int k = i; k < j ; k ++){
int t = m[i][k] + m[k+1][j] + p[i-1]*p[j]*p[k];
if(t < m[i][j]){
m[i][j] = t;
s[i][j] = k;
}
}
}
}
println();
System.out.println("最少相乘次数:" + m[1][n]);
System.out.print("矩阵划分结果: ");
partation(1,6);
}
}
// p[] 矩阵的维数
// m[][] m[i][j] 表示[Ai..Aj]的最少相乘次数
// s[][] 断点位置
public class beiwanglu {
static int inf = 0x3f3f3f3f;
static int n = 6;
static int p[] = {30,35,15,5,10,20,25};
static int m[][] = new int[n+1][n+1];
static int s[][] = new int[n+1][n+1];
public static int lookupChain(int i, int j){
if(m[i][j] > 0) return m[i][j];
if(i == j) return 0;
m[i][j] = inf;
//尝试插入断点K
for(int k = i; k < j; k ++){
int t = lookupChain(i, k)+lookupChain(k+1, j)+p[i-1]*p[k]*p[j];
if(t < m[i][j]){
m[i][j] = t;
s[i][j] = k;
}
}
return m[i][j];
}
public static void init(){
for(int i = 1; i <= n; i ++)
for(int j = i; j <=n; j ++)
s[i][j] = m[i][j] = 0;
}
public static void println(){
System.out.println("m[][]: ");
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++)
System.out.print(m[i][j] +" ");
System.out.println();
}
System.out.println("s[][]: ");
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++)
System.out.print(s[i][j] +" ");
System.out.println();
}
}
public static void partation(int i, int j){
if(i == j){
System.out.print("A" + i);
}else {
System.out.print("(");
partation(i, s[i][j]);
partation(s[i][j]+1,j);
System.out.print(")");
}
}
public static void main(String[] args){
init(); //初始化数组
lookupChain(1,6);
println();
System.out.println("最少相乘次数:" + m[1][n]);
System.out.print("矩阵划分结果: ");
partation(1,6);
}
}