IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【动态规划】—— 数字三角形 -> 正文阅读

[数据结构与算法]【动态规划】—— 数字三角形


动态规划

动态规划算法把原算法视作若干个重叠子问题的逐层递进,每个子问题的求解过程都构成一个“阶段”。在完成前一个阶段的计算之后,动态规划才会执行下一个阶段的计算。

为了保证这些计算能够按顺序、不重复地进行,动态规划要求已经求解的子问题不受后续阶段的影响。这个条件也叫“无后效性”。换言之,动态规划对状态空间的遍历构成一张有向无环图,遍历顺序就是该有向无环图的一个拓扑序。有序无环图中的节点对应问题中的“状态”,图中的边则是对应状态之间的“转移”,转移的选取就是动态规划中的“决策”

在很多情况下,动态规划用于求解最优化问题。此时,下一阶段的最优解应该能够由前前面各阶段的子问题的最优解求出。这个条件被称为“最优子结构性质”。

“状态”“阶段”“决策”是构成动态规划算法的三要素,而“子问题重叠性”“无后效性”“最优子结构性”是问题能用动态规划求解的三个基本条件。

动态规划算法把相同的计算过程作用于各阶段的同类子问题,就好像把一个固定的公式套在格式相投的若干输入数据上运行。因此,我们一般只需要定义出DP的计算过程,就可以编程实现了,这个计算过程就称为“状态转移方程”。

闫式思考法

集合的角度来思考问题:?


例题:AcWing 1015. 摘花生


集合含义:所有从?\small (1,1) ?走到?\small (i,j) ?的所有路线的最大值?

在状态计算中,很重要的划分依据:“最后”

集合的划分依据1.不重 2.不漏(在不重复这一点是,可以出现重复算,因为最后是取子集的最最值)


AC代码?

#include <iostream>
#include <cstring>
using namespace std;

const int N = 110;

int n, m;
int w[N][N];
int f[N][N];

int main()
{
    int T; cin >> T;
    while(T -- )
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i ++ )
            for(int j = 1; j <= m; j ++ ) 
                scanf("%d", &w[i][j]);
        
        for(int i = 1; i <= n; i ++ )
            for(int j = 1; j <= m; j ++ )
                f[i][j] = max(f[i][j - 1], f[i - 1][j]) + w[i][j];
        cout << f[n][m] << endl;
    }
    return 0;
}

例题:AcWing 1018. 最低通行费?


跟上面的摘花生的是类似的题目类型。多了时间上面的限制(?\small \leqslant 2n-1?)

这个时间上面的限制 等价于 不走回头路

由于所求的是最小值,这道题在求解的时候需要对边界进行初始化


AC代码

#include <iostream>
#include <cstring>
using namespace std;

const int N = 210, INF = 0x3f3f3f3f;

int n;
int w[N][N];
int f[N][N];


int main()
{
    cin >> n;
    
    for(int i = 1; i <= n; i ++ )
        for(int j = 1; j <= n; j ++ )
            scanf("%d", &w[i][j]);
    
    for(int i = 1; i <= n; i ++ )
        for(int j = 1; j <= n; j ++ )
            if(i == 1 && j == 1) f[i][j] = w[i][j];
            else 
            {
                f[i][j] = INF;
                if(i > 1) f[i][j] = min(f[i][j], f[i - 1][j] + w[i][j]);
                if(j > 1) f[i][j] = min(f[i][j], f[i][j - 1] + w[i][j]);
            }
            
    cout << f[n][n] << endl;        
    return 0;
} 

例题:AcWing 1027. 方格取数

输入样例:

8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0

输出样例:

67

这一题相比于前面两题,多了总共走两次这样的限制条件。?

在只走一次的情况中:

\small f[i,j]?表示的是?所有从?\small (1,1) ?走到?\small (i,j) ?的所有路线的最大值?

\small f[i,j]=max(f[i - 1][j],f[i][j-1]) +w[i][j]

走两次的情况中:

\small f[i_1,i_2,j_1,j_2]?表示所有从?\small (1,1)\small (1,1)?走到?\small (i_1,j_1),(i_2,j_2)?的路径的所有集合的最大值

如何处理“同一个格子不能被重复选择”?

只有在?\large {\color{Blue} i_1+j_1=i_2+j_2}?时,两条路径的格子才会重合?

\small k=i_1+j_1=i_2+j_2??表示两个人同时走 k 步(横纵坐标之和)(类比摘花生)

\small f[k,i_1,i_2]?表示所有从??\small (1,1),?\small (1,1)?分别走到?\small (i_1,k-i_1),(i_2,k-i_2)?的路径的最大值


AC代码?

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 15;

int n;
int w[N][N];
int f[N * 2][N][N];

int main()
{
    cin >> n;
    int a, b, c;
    while(cin >> a >> b >> c, a || b || c) w[a][b] = c;
    
    for(int k = 2; k <= n + n; k ++ )
        for(int i1 = 1; i1 <= n; i1 ++ )
            for(int i2 = 1; i2 <= n; i2 ++ )
            {
                int j1 = k - i1, j2 = k - i2;
                if(j1 >= 1 && j1 <= n && j2 >= 1 && j2 <= n)
                {
                    int t = w[i1][j1];
                    if(i1 != i2) t += w[i2][j2];
                    int &x = f[k][i1][i2];
                    x = max(x, f[k - 1][i1 - 1][i2 - 1] + t);
                    x = max(x, f[k - 1][i1 - 1][i2] + t);
                    x = max(x, f[k - 1][i1][i2 - 1] + t);
                    x = max(x, f[k - 1][i1][i2] + t);
                }
            }
    cout << f[n + n][n][n];
    return 0;
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-06-25 18:20:58  更:2022-06-25 18:23:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 2:01:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码