动态规划算法设计

动态规划算法设计

标签(空格分隔): 算法知识文档 动态规划


动态规划设计要素

  1. 问题建模,优化的目标函数是什么?约束条件是什么?
  2. 如何划分子问题(边界)?
  3. 问题的优化函数值与子问题的优化函数值之间存在着什么以来关系?(递推方程)
  4. 是否满足优化原则?
  5. 最小子问题怎样界定?其优化函数值,即初始值等于什么?

矩阵链相乘

问题:

A1,A2,...,An A 1 , A 2 , . . . , A n 为矩阵序列, Ai A i Pi1Pi P i − 1 ∗ P i 阶矩阵, i=1,2,...,n i = 1 , 2 , . . . , n 试确定矩阵的乘法顺序,使得元素相乘的总次数最少.

输入:

向量 P=<P0,P1,...,Pn>, P =< P 0 , P 1 , . . . , P n > , 其中 P0,P1,...,Pn P 0 , P 1 , . . . , P n n n 个矩阵的行数与列数,比如P0是第一个矩阵的行数, P1 P 1 是第一个矩阵的列数同时是第二个矩阵的行数,以此类推. pn p n 是第 n1 n − 1 个矩阵的行数,是第 n n 个矩阵的列数.

输出:

矩阵链乘法加括号的位置

矩阵相乘基本运算次数

矩阵A: i i j列, B B : j k k 列,以元素相乘作为基本运算,计算AB的工作量, AB=C,C A B = C , C i i k列个元素,计算每一个元素需要做的乘法次数是 j j 次,所以计算AB需要做 ijk i ∗ j ∗ k 次乘法.

实例:

输入:
P=<10,100,5,50> P =< 10 , 100 , 5 , 50 >
A1:10100,A2:1005,A3:550 A 1 : 10 ∗ 100 , A 2 : 100 ∗ 5 , A 3 : 5 ∗ 50

乘法次序:
(A1A2)A3:101005+10550=7500 ( A 1 A 2 ) A 3 : 10 ∗ 100 ∗ 5 + 10 ∗ 5 ∗ 50 = 7500
A1(A2A3):100550+1010050=75000 A 1 ( A 2 A 3 ) : 100 ∗ 5 ∗ 50 + 10 ∗ 100 ∗ 50 = 75000

第一种次序计算次数最少

蛮力算法:
枚举所有加上括号的可能,复杂度是指数级的.

动态规划算法

子问题的划分:
Ai...j A i . . . j : 矩阵链 Ai,Ai+1,...,Aj, A i , A i + 1 , . . . , A j , 边界 i,j i , j 输入向量 <Pi1,Pi,...,Pj> < P i − 1 , P i , . . . , P j > <script type="math/tex" id="MathJax-Element-33"> </script>其最好划分的运算次数是: m[i,j] m [ i , j ]

子问题的依赖关系:
最优划分最后一次相乘发生在矩阵 k k 的位置,即:

Ai...j=Ai...kAk+1...j

Ai...j A i . . . j 最优运算次数依赖于 Ai...k A i . . . k Ak+1...j A k + 1... j 的最优运算次数. k[i,j) k ∈ [ i , j )

解:
计算得到 Ai...j A i . . . j 最少乘法次数: m[i][j] m [ i ] [ j ]
下面是计算 m[i][j] m [ i ] [ j ]

{0minik<j{m[i,k]+m[k+1,j]+Pi1PkPj}i = ji < j { 0 i = j min i ≤ k < j { m [ i , k ] + m [ k + 1 , j ] + P i − 1 P k P j } i < j

也就是说计算得到 Ai...k A i . . . k Pi1 P i − 1 Pk P k 列的矩阵,计算 Ak+1...j A k + 1... j 得到 Pk P k Pj P j 列的矩阵.最后这两个矩阵相乘得到 Pi1 P i − 1 Pj P j 列的矩阵,计算过程取最小就相当于最优决策,当前的最优决策序列是相对于初始和结束的最优决策序列.

实战:Multiplication Puzzle

Language:
Multiplication Puzzle
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 11799 Accepted: 7316

Description

The multiplication puzzle is played with a row of cards, each containing a single positive integer. During the move player takes one card out of the row and scores the number of points equal to the product of the number on the card taken and the numbers on the cards on the left and on the right of it. It is not allowed to take out the first and the last card in the row. After the final move, only two cards are left in the row.

The goal is to take cards in such order as to minimize the total number of scored points.

For example, if cards in the row contain numbers 10 1 50 20 5, player might take a card with 1, then 20 and 50, scoring
10150+50205+10505=500+5000+2500=8000 10 ∗ 1 ∗ 50 + 50 ∗ 20 ∗ 5 + 10 ∗ 50 ∗ 5 = 500 + 5000 + 2500 = 8000

If he would take the cards in the opposite order, i.e. 50, then 20, then 1, the score would be
15020+1205+1015=1000+100+50=1150. 1 ∗ 50 ∗ 20 + 1 ∗ 20 ∗ 5 + 10 ∗ 1 ∗ 5 = 1000 + 100 + 50 = 1150.

Input
The first line of the input contains the number of cards N (3 <= N <= 100). The second line contains N integers in the range from 1 to 100, separated by spaces.

Output
Output must contain a single integer - the minimal score.

Sample Input
6
10 1 50 50 20 5

Sample Output
3650

Source
Northeastern Europe 2001, Far-Eastern Subregion

轻松Accept:

CODE: C O D E :

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define MAX_N 105
typedef long long LL;
LL dp[MAX_N][MAX_N], p[MAX_N];
int s[MAX_N][MAX_N]; // 标记括号位置
int N;

// 打印追踪解的结果
void printS(){
    int i,j;
    for(i = 1; i <= N-1; i++){
        for(j = 1; j <= N-1; j++){
            printf("%d ", s[i][j]);
        }
        printf("\n");
    }
}

void solve(){
    int r,i,j,k;
    LL tmp;
    for(i = 1; i <= N-1; i++) dp[i][i] = 0; // 子问题是1,就是一个矩阵没有相乘次数
    for(r = 2; r <= N-1; r++){ // 子问题的长度[2, N-1]
        for(i = 1; i <= N-1; i++){ // 计算长度是r的子问题
            j = i+r-1; // 右边界
            if(j > N-1) continue; // j的范围
            else {  
                dp[i][j] = dp[i+1][j] + p[i-1]*p[i]*p[j]; // k=i的时候
                s[i][j] = i; // 追踪解
                for(k = i+1; k <= j-1; k++){
                    tmp = dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j];
                    if(dp[i][j] > tmp) {
                        dp[i][j] = tmp; // 更新解
                        s[i][j] = k; // 追踪解
                    }
                }
            }
        }
    }
    printf("%lld\n", dp[1][N-1]);
}

int main(){
    freopen("in.txt", "r", stdin);
    int i;
    while(~scanf("%d", &N) && N){
        for(i = 0; i < N; i++) scanf("%lld", &p[i]);
        solve();
    }
}

问题描述:

小结:

动态规划算法设计要素:

  • 多阶段决策过程,每一步处理一个子问题,界定子问题的边界
  • 列出优化函数的递推方程及初始值
  • 问题要满足优化原则或最优子结构性质,即:一个最优决策序列的任何子序列本身一定是相对于子序列的初始和结束状态的最优决策序列.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值