通过上一章对01背包问题的学习,我相信同学们都动态规划都有了一个新的认识。在我们利用动态规划解决问题的过程通常会有以下几个常见的专业术语,分别是:状态定义,状态的转移,初始化和边界条件。下面我们对这几个专业术语做一个简单的介绍。

状态定义 就是定义子问题,如何表示目标规模的问题和更小规模的问题。例如常见的方法:定义状态 dp[n],表示规模为 n 的问题的解,dp[n - 1] 就表示规模为 n - 1 的子问题的解。在实战中 dp[n] 的具体含义需要首先整理清楚再往下做。

状态转移 就是子问题之间的关系,例如定义好状态 dp[n],此时子问题是 dp[n-1] 等,并且大规模的问题的解依赖小规模问题的解,此时需要知道怎样通过小规模问题的解推出大规模问题的解。这一步就是列状态转移方程的过程。一般的状态转移方程可以写成如下形式

dp[n] = f(dp[i]) 其中 i < n

Copy

按照状态定义和状态转移的常见形式,可以对动态规划进行分类。

线性动态规划简介

线性动态规划的主要特点是状态的推导是按照问题规模 i 从小到大依次推过去的,较大规模的问题的解依赖较小规模的问题的解。

这里问题规模为 i 的含义是考虑前 i 个元素 [0..i] 时问题的解。

状态定义:

dp[n] := [0..n] 上问题的解

Copy

状态转移:

dp[n] = f(dp[n-1], ..., dp[0])

Copy

从以上状态定义和状态转移可以看出,大规模问题的状态只与较小规模的问题有关,而问题规模完全用一个变量 i 表示,i 的大小表示了问题规模的大小,因此从小到大推 i 直至推到 n,就得到了大规模问题的解,这就是线性动态规划的过程。

按照问题的输入格式,线性动态规划解决的问题主要是单串,双串,矩阵上的问题,因为在单串,双串,矩阵上问题规模可以完全用位置表示,并且位置的大小就是问题规模的大小。因此从前往后推位置就相当于从小到大推问题规模。

线性动态规划是动态规划中最基本的一类。问题的形式、dp 状态和方程的设计、以及与其它算法的结合上面变化很多。按照 dp 方程中各个维度的含义,可以大致总结出几个主流的问题类型,见后面的小节。除此之外还有很多没有总结进来的变种问题,小众问题,和困难问题,这些问题的解法更多地需要结合自己的做题经验去积累。

下面从一个经典的例题说起:

数字三角形

[P1693 数字三角形 I - TopsCoding]

[算法分析]

方法一:递归求解

用二维数组存放数字三角形,f( x, y) 表示第x行的第 y 个数字(x,y从1 开始算)

sum(x,y ) : 从f(x,y)到底边的各条路径中,最佳路径的数字之和。从f(x, y)出发,下一步只能走f(x+1,y)或者f(x+1,y+1)。故对于N行的三角形,完整代码如下所示:

#include <iostream>
using namespace std;
int f[101][101];
int num;
int sum(int x, int y)
{if(x == num)             //当加到最后一行 递归结束return f[x][y];else return max(sum(x+1, y),sum(x+1, y + 1))+ f[x][y]; //选取左孩子或者右孩子最大的那个
}
int main()
{int i, j;cin >> num;for(i = 1; i <= num; i ++)for(j = 1; j <= i; j ++)cin >> f[i][j];cout << sum(1,1) ;return 0;
}

Copy

方法2:动态规划

1.确定状态:

题目要求从(1,1)出发到最底层路径最大权值和,路径是由各个点串联而成,路径起点固定,终点和中间点相对不固定。

因此定义f[x][y]表示从(1,1)出发到达(x,y)的路径最大权值和。最终答案如下:

ans = max{F[N][1], f[N][2], ..., f[N][N]}

2.确定状态转移方程和边界条件

先不考虑从(1,1)到(x,y)的每一步是怎么走的,只考虑最后一步,根据最后一步是向左还是向右分成以下两种情况:

​ (1)向左,那么最大权值和为f[x-1][y] + a[x][y]

​ (2)向右,那么最大权值和为f[x-1][y-1] + a[x][y]

综和上述两种情况,那么最后的(x,y)的最大权值和就是 max{f[x-1][y], f[x-1][y-1]} + a[x][y]

状态转移方程就是 f[x][y] = max{f[x-1][y], f[x-1][y-1]} + a[x][y]

边界条件:f[1][1] = a[1][1]

完整代码如下所示:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int a[MAXN][MAXN], f[MAXN][MAXN], N;int main()
{cin >> N;for (int i = 1; i <= N; i++){for (int j = 1; j <= i; j++){cin >> a[i][j];}}f[1][1] = a[1][1];//动规边界条件for (int i = 1; i <= N; i++){for (int j = 1; j <= i; j++){f[i][j] = max(f[i - 1][j - 1], f[i - 1][j]) + a[i][j];}}int ans = 0;for (int i = 1; i <= N; i++){ans = max(ans, f[N][i]);}cout << ans;return 0;
}

Copy

方法三:动态规划改进

想一想,下面的代码是如何进行改进的?

#include <cstdio>
#include <iostream>
using namespace std;
const int N = 110;
int n, a[N][N], f[N][N];
int main() {cin >> n;for (int i = 1; i <= n; i++)for (int j = 1; j <= i; j++) cin >> a[i][j];for (int i = n; i >= 1; i--)for (int j = 1; j <= i; j++)f[i][j] = max(f[i + 1][j], f[i + 1][j + 1]) + a[i][j];cout << f[1][1];return 0;
}

Copy

取数(max)

庐阳区2020年压轴题

[P2645 取数(max) - TopsCoding]

[算法分析]

根据题意,当我们取走球x的时候,同时还可以取走其他分值为x的球,因此考虑使用桶排序。

题目中有一个限制:当你取球x的时候,球x-1或球x+1就不能被取了,因此取不取球需要作出选择。

如果不取这个球,分值还是之前的分值即f[i-1];

如果取这个球,分值等于球x分值乘以球x的个数,同时由于不能去x-1的球,因此这个时候的分值为t[i]*i+f[i-2]。

结合样例:首先进行数组标记,3出现2次,4出现1次,5出现2次。

首先去1号球,0分,接着取2号球0分;

当取3号球的时候,f[3]=max(t[i]*i+f[i-2],f[i-1])=max(t[3]*3+f[1],f[2])=max(6,0)=6;

当取4号球的时候,f[4]=max(t[i]*i+f[i-2],f[i-1])=max(t[4]*4+f[2],f[3])=max(4,6)=6;

当取5号球的时候,f[5]=max(t[i]*i+f[i-2],f[i-1])=max(t[5]*5+f[3],f[4])=max(16,6)=16;

故最后的答案为16。

完整的代码如下所示:

#include<bits/stdc++.h>
using namespace std;
int main()
{int n;long long a,s,t[1000002],m=0,f[1000002];cin>>n;for(int i=1;i<=n;i++){cin>>a;t[a]++;   //数组标记,把球放到对应分值的桶里面m=max(m,a);  //求出球的最大分值,减少循环的范围}f[1]=t[1];  //初始化for(int i=2;i<=m;i++){  //从第2个球开始循环f[i]=max(t[i]*i+f[i-2],f[i-1]);  //核心代码}cout<<f[m];return 0;
}

Copy

体验积分值(point)

2017年合肥市压轴题

[P1525 体验积分值(point) - TopsCoding]

[算法分析]

看完上一题之后,这一题就更简单了,所有的项目排成一排,每个项目只能玩一次,相当于排好序了。

不能游玩任意相邻的两个项目是什么意思呢?其实就是上题中当你取球x的时候,就不可以取球x-1和x-2了。

因此本题的动态转移方程跟上面的完全一致,即dp[i]=max(dp[i-2]+a[i],dp[i-1]);

完整的代码如下所示:

#include<bits/stdc++.h>
using namespace std;
int n,a[1010],dp[1010];
int main(){cin>>n;for(int i=1;i<=n;i++){cin>>a[i];}dp[1]=a[1];  //初始化for(int i=2;i<=n;i++){dp[i]=max(dp[i-2]+a[i],dp[i-1]);  //动态转移方程}cout<<dp[n];return 0;
}

Copy

最长上升子序列

最长上升子序列(Longest Increasing Subsequence),简称LIS,也有些情况求的是最长非降序子序列,二者区别就是序列中是否可以有相等的数。假设我们有一个序列 b i,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们也可以从中得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N,但必须按照从前到后的顺序。比如,对于序列(1, 7, 3, 5, 9, 4, 8),我们就会得到一些上升的子序列,如(1, 7, 9), (3, 4, 8), (1, 3, 5, 8)等等,而这些子序列中最长的(如子序列(1, 3, 5, 8) ),它的长度为4,因此该序列的最长上升子序列长度为4。 是不是觉得好抽象~没事我给你解释~

首先需要知道,子串和子序列的概念,我们以字符子串和字符子序列为例,更为形象,也能顺带着理解字符的子串和子序列:

(1)字符子串指的是字符串中连续的n个字符,如abcdefg中,ab,cde,fg等都属于它的字串。

(2)字符子序列指的是字符串中不一定连续但先后顺序一致的n个字符,即可以去掉字符串中的部分字符,但不可改变其前后顺序。如abcdefg中,acdg,bdf属于它的子序列,而bac,dbfg则不是,因为它们与字符串的字符顺序不一致。

知道了这个,数值的子序列就很好明白了,即用数组成的子序列。这样的话,最长上升子序列也很容易明白了,归根结底还是子序列,然后子序列中,按照上升顺序排列的最长的就是我们最长上升子序列了,这样听来是不是就很容易明白啦~

还有一个非常重要的问题:请大家用集合的观点来理解这些概念,子序列、公共子序列以及最长公共子序列都不唯一,但很显然,对于固定的数组,虽然LIS序列不一定唯一,但LIS的长度是唯一的。再拿我们刚刚举的栗子来讲,给出序列 ( 1, 7, 3, 5, 9, 4, 8),易得最长上升子序列长度为4,这是确定的,但序列可以为 ( 1, 3, 5, 8 ), 也可以为 ( 1, 3, 5, 9 )

LIS长度的求解方法:
那么这个到底该怎么求呢?

动态规划:
  我们都知道,动态规划的一个特点就是当前解可以由上一个阶段的解推出, 由此,把我们要求的问题简化成一个更小的子问题。子问题具有相同的求解方式,只不过是规模小了而已。最长上升子序列就符合这一特性。我们要求n个数的最长上升子序列,可以求前n-1个数的最长上升子序列,再跟第n个数进行判断。求前n-1个数的最长上升子序列,可以通过求前n-2个数的最长上升子序列……直到求前1个数的最长上升子序列,此时LIS当然为1。

  让我们举个例子:求 2 7 1 5 6 4 3 8 9 的最长上升子序列。我们定义d(i) (i∈[1,n])来表示前i个数以A[i]结尾的最长上升子序列长度。

  前1个数 d(1)=1 子序列为2;

  前2个数 7前面有2小于7 d(2)=d(1)+1=2 子序列为2 7

  前3个数 在1前面没有比1更小的,1自身组成长度为1的子序列 d(3)=1 子序列为1

  前4个数 5前面有2小于5 d(4)=d(1)+1=2 子序列为2 5

  前5个数 6前面有2 5小于6 d(5)=d(4)+1=3 子序列为2 5 6

  前6个数 4前面有2小于4 d(6)=d(1)+1=2 子序列为2 4

  前7个数 3前面有2小于3 d(3)=d(1)+1=2 子序列为2 3

  前8个数 8前面有2 5 6小于8 d(8)=d(5)+1=4 子序列为2 5 6 8

  前9个数 9前面有2 5 6 8小于9 d(9)=d(8)+1=5 子序列为2 5 6 8 9

  d(i)=max{d(1),d(2),……,d(i)} 我们可以看出这9个数的LIS为d(9)=5

  总结一下,d(i)就是找以A[i]结尾的,在A[i]之前的最长上升子序列+1,当A[i]之前没有比A[i]更小的数时,d(i)=1。所有的d(i)里面最大的那个就是最长上升子序列。其实说的通俗点,就是每次都向前找比它小的数和比它大的数的位置,将第一个比它大的替换掉,这样操作虽然LIS序列的具体数字可能会变,但是很明显LIS长度还是不变的,因为只是把数替换掉了,并没有改变增加或者减少长度。但是我们通过这种方式是无法求出最长上升子序列具体是什么的,这点和最长公共子序列不同。

完整代码如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 103;
int a[maxn], f[maxn];
int n,ans = INT_MIN;
int main()
{cin>>n;for(int i=1; i<=n; i++) {cin>>a[i];f[i] = 1;}for(int i=1; i<=n; i++)for(int j=1; j<i; j++)if(a[j] < a[i])f[i] = max(f[i], f[j]+1);for(int i=1; i<=n; i++) ans = max(ans, f[i]);cout<<ans;return 0;
}

Copy

最长不下降子序列

[最长不下降子序列][P1350 最长不下降子序列 - TopsCoding]

[算法分析]

自行补充

完整代码如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1003;
int a[maxn], f[maxn];
int n,ans = INT_MIN;
int main()
{cin>>n;for(int i=1; i<=n; i++) {cin>>a[i];f[i] = 1;}for(int i=1; i<=n; i++)for(int j=1; j<i; j++)if(a[j] <= a[i])f[i] = max(f[i], f[j]+1);for(int i=1; i<=n; i++) ans = max(ans, f[i]);cout<<ans;return 0;
}

Copy

最长公共子序列

最长公共子序列

[P1180 最长公共子序列 - TopsCoding]

[算法分析]

较难,了解即可。

方法一:

include <bits/stdc++.h>
using namespace std;
int f[201][201];
string a,b;
int main()
{cin>>a>>b;int i,j;for(i=0;i<201;i++){f[i][0]=0;f[0][j]=0;}for(i=1;i<=a.size();i++){for(j=1;j<=b.size();j++){int m=0;int k=j-1;for(k=j-1;k>=0;k--){if(b[k]==a[i-1])break;}if(k>=0){m=max(f[i-1][j],f[i-1][k]+1);}else{m=f[i-1][j];}for(k=i-1;k>=0;k--){if(a[k]==b[j-1]){break;}}if(k>=0){m=max(f[k][j-1]+1,m);m=max(m,f[i][j-1]);}else{m=max(m,f[i][j-1]);}f[i][j]=m;}}cout<<f[a.size()][b.size()];
}

Copy

方法二:

#include <cstdio>
#include <iostream>
using namespace std;
const int N = 210;
int f[N][N];
string s1, s2;
int main() {cin >> s1 >> s2;int n = s1.size(), m = s2.size();for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++) {if (s1[i - 1] == s2[j - 1])f[i][j] = f[i - 1][j - 1] + 1;elsef[i][j] = max(f[i - 1][j], f[i][j - 1]);}cout << f[n][m];return 0;
}

Copy

导弹拦截 [missile]

某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭,并观测到导弹依次飞来的高度,请计算最少需要多少套系统才能拦截所有导弹。拦截来袭导弹时,必须按来袭导弹袭击的时间顺序,不允许先拦截后面的导弹,再拦截前面的导弹。
输入
输入有两行,第一行,输入雷达捕捉到的敌国导弹的数量k(k<=10000),第二行,输入k个整数,表示k枚导弹的高度(高度可以为负,导弹可以在海里拦截),按来袭导弹的袭击时间顺序给出,以空格分隔。
输出
只有一行,包含两个整数,用空格分开
第1个数表示一套系统最多打多少导弹;
第2个数表示最少需要多少套系统才能拦截所有导弹。
样例输入

4
9 6 7 8
1
2

Copy

样例输出

2 3

Copy

[算法分析]

问题1∶导弹拦截的高度只能和上一次的拦截高度相同或者更低,故最长不上升子序列的长度就是问题1的答案。

定义状态∶ d[i]表示以i结尾的最长不上升子序列的长度,答案∶ans= max(d[i]);

求解d[i]时,对A[i]做决策,最多有i种选择∶

① A[i]独立一个子序列,此时d[1] = 1;

② A[i]和a[1]接在一起,此时∶ d[i] = d[1] +1;(A[1] >= A[i]);

③ A[i]和a[2]接在一起,此时∶ d[i] = d[2] + 1;(A[2] >= A[i);

④ ......

⑤ A[i]和aji-1]接在一起,此时∶ d[i] =di-1] +1;(A[i-1]>= A[i]);

状态转移方程∶ d[i] = max(d[j]) +1;(j<i&& a[j]>= a[i])。

问题2∶ 一个不下降子序列需要一套系统,最少的不下降子序列数量就是问题2的答案.

最少不下降子序列的数量=最长上升子序列的长度,问题转换为求最长上升子序列。

定义状态∶f[i]表示以i结尾的最长上升子序列的长度,答案∶ ans= max(f[i]);

求解f[i]时,对A[i]做决策,最多有i种选择∶

① A[i]独立一个子序列,此时f[i] = 1;

② A[i]同a[1]接在一起,此时∶ f[i] = f[1] + 1;(A[1] < A[i);

③ A[i]和a[2]接在一起,此时∶f[i] = f|2]+1; (A[2]<A[i]);

④ ......

⑤ A[i]和ai-1]接在一起,此时: f[i]= f[i-1]+ 1; (A[i]-1]< A[i]);

状态转移方程∶f[i] = max(f[j])+ 1;(j<i&& a[j] <a[i])。

完整代码如下:

#include<cstdio>
#include<iostream>
using namespace std;
int v[10005],f[10005],g[10005]={0,1},maxn,minn;
//maxn表示最长上升子序列长度,minn表示最长下降子序列的长度
int main()
{int n;scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&v[i]); //输入每枚导弹的高度f[i]=g[i]=1; for(int j=1;j<i;j++){if(v[i]<=v[j]) //求最长上升子序列{f[i]=max(f[i],f[j]+1);}if(v[i]>v[j]) //求最长下降子序列{g[i]=max(g[i],g[j]+1);}}if(f[i]>maxn) //求出最长上升子序列的长度{maxn=f[i];}if(g[i]>minn) //求出最长下降子序列的长度{minn=g[i];}}printf("%d %d\n",maxn,minn); /*输出最长上升子序列长度与最长下降子序列的长度,也就是需要多少套拦截系统与一套系统最多拦截多少枚导弹*/return 0;
}
//本题将经典的动态规划的模板融入进题干里,关键是要把它挖掘出来,就成功了!

Copy

猫捉老鼠

Tom是一只捉鼠经验丰富的猫,趁着月黑风高,Tom打算“清理”一条“老鼠街”上的老鼠。

这条老鼠街上一共有N个老鼠洞,每个老鼠洞中都有一些老鼠(当Tom清理一个老鼠洞时,这个洞中的所有老鼠都被捉到)。

Tom事先调查得知,只有当它同时“清理”了两个连续的老鼠洞时,老鼠街上的报警系统才会启动,然后老鼠们就会集体逃跑。作为一向谨慎的猫,Tom不愿意让这种情况出现。

它想知道,在不惊动报警系统的情况下,今晚能捉到多少只老鼠?

输入格式

输入的第一行是一个整数 T (T <= 50) ,表示一共有 T 组数据。
接下来的每组数据,第一行是一个整数 N (1 <= N <= 100, 000) ,表示一共有 N 个老鼠洞。第二行是 N 个被空格分开的正整数,表示每个老鼠洞中老鼠的数量,每个老鼠洞中老鼠的数量均不超过 1000 。

输出格式

对于每组数据,输出一行。该行包含一个整数,表示Tom在不惊动报警系统的情况下,可以捉到的老鼠的数量

输入输出样列

输入样例1:

2
3
1 8 2
4
10 7 6 14

Copy

输出样例1:

8
24

Copy

说明

【样例说明】

对于第一组样例,Tom选择第 2 个老鼠洞,捉住的老鼠数量为 8 。
对于第二组样例,Tom选择第 1 和 4 个老鼠洞,捉住的老鼠数量为 10 + 14 = 24 。

[算法分析]

问题目标是捉到尽可能多的老鼠,将每个老鼠洞划分为一个阶段,对每个老鼠洞有两种决策∶"清理"或者"不清理。该问题是一个典型的多阶段决策最优化问题。

定义状态∶d[i]表示"清理"前i个老鼠洞可以捉到的最大老鼠数量,答案ans= d[n]。

求解d[i]时,对老鼠洞i做决策,有2种选择∶

清理第i个老鼠洞∶ 可以捉到a[i]只老鼠,同时由于不能清理连续的老鼠洞,所以Tom不能清理第i-1个老鼠洞,要捉到最多的老鼠,就要从前i-2个老鼠洞中捉到尽量多的老鼠,此时∶ d[i] = d[i-2]+ a[i]。

② 不清理第i个老鼠洞,此时如果要做到最多的老鼠,就要从前i-1个老鼠洞中捉到尽量多的老鼠,此时∶d[i] = d[i-1];

状态转移方程∶ 取两种方案的最大值d[i] = max(d[i-1], d[i-2]+ a[i]);

初始化∶ d[0] = 0; 当i==1时,i-2是负数,所以要先初始化d[1] = a[1];

完整代码如下所示:

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int t,n,m,d[N];
int main()
{cin>>t;while(t--){scanf("%d %d",&n,&d[1]);for(int i=2;i<=n;i++){scanf("%d",&m);  //读取第i个老鼠洞的老鼠数量 d[i]=max(d[i-1],d[i-2]+m); }printf("%d\n",d[n]);}return 0;
}

Copy

第十七章:线性动态规划相关推荐

  1. 动态规划法求最大字段和时间复杂度_九章算法 | 动态规划:最长上升子序列

    给定一个整数序列,找到最长上升子序列(LIS),返回LIS的长度. 在线评测地址:LintCode 领扣 说明 最长上升子序列的定义: 最长上升子序列问题是在一个无序的给定序列中找到一个尽可能长的由低 ...

  2. 程序员编程艺术第二十七章:不改变正负数相对顺序重新排列数组(无解?)

    第二十七章:不改变正负数之间相对顺序重新排列数组.时间O(N),空间O(1) 前言 本文开始之前,顺道说个事:CSDN最近开始评选10大博客专栏,投票地址为:http://event.blog.csd ...

  3. 数据结构思维 第十七章 排序

    第十七章 排序 原文:Chapter 17 Sorting 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 计算机科学领域过度痴迷于排序算法.根据 CS 学生在这个主题上花费的时 ...

  4. 第二十七章 数论——快速幂与逆元

    第二十七章 快速幂与扩展欧几里德算法 一.快速幂 1.使用场景 2.算法思路 (1)二进制优化思想 (2)模运算法则 3.代码实现 (1)问题 (2)代码 二.快速幂求逆元 1.什么是逆元? (1)同 ...

  5. 程序员编程艺术第一~二十七章集锦与总结(教你如何编程),及PDF免分下载

    程序员编程艺术第一~二十七章集锦与总结(教你如何编程) 作者:July.编程艺术室 出处:结构之法算法之道blog 一.引言 自从去年7月份朋友花明月黯帮我制作了十三个经典算法研究的PDF文档(最新的 ...

  6. 游戏感:虚拟感觉的游戏设计师指南——第十七章 游戏感的原理

    这是一本游戏设计方面的好书 转自天:天之虹的博客:http://blog.sina.com.cn/jackiechueng 感谢天之虹的无私奉献 Word版可到本人的资源中下载 第十七章游戏感的原理 ...

  7. 【控制】《最优控制理论与系统》-胡寿松老师-第5章-线性最优状态调节器

    第4章 回到目录 第6章 <最优控制理论与系统>-胡寿松老师-第5章-线性最优状态调节器 第5章 线性最优状态调节器 5.1 线性二次型问题 5.2 状态调节器 5.2.1 有限时间状态调 ...

  8. 【控制】《现代控制理论》谢克明老师-第3章-线性控制系统的能控性和能观测性

    第2章 回到目录 第4章 第3章-线性控制系统的能控性和能观测性 3.1 系统的能控性 3.2 系统的能观测性 3.3 能控性和能观测性的对偶关系 3.4 单输入单输出系统的能控标准型和能观测标准型 ...

  9. 【控制】《现代控制理论》谢克明老师-第2章-线性控制系统状态空间表达式的求解

    第1章 回到目录 第3章 第2章-线性控制系统状态空间表达式的求解 2.1 线性定常连续系统齐次状态方程的解 2.2 线性定常连续系统的状态转移矩阵 2.3 线性定常连续系统非齐次状态方程的求解 2. ...

最新文章

  1. 第 138 章 Spark
  2. TensorFlow学习笔记(一):数据操作指南
  3. 用户,群组和权限 二
  4. OkHttp实现分析之Websocket
  5. 2进制、8进制、10进制、16进制...各种进制间的轻松转换(c#)
  6. Java中List的排序
  7. VIPKID义务援手韦博英语,承接其“嗨英语”部分学员
  8. Resource is out of sync with the file system解决办法
  9. [tips]ubuntu 12.04系统黑屏
  10. 模糊控制在matlab的实现,模糊控制系统的MATLAB实现
  11. 用python开发手机游戏_python开发安卓app
  12. 如何使用Git上传本地项目到github?(mac版)
  13. 新一轮众筹淘金热——DAOs
  14. scikit-learn广义线性模型之最小二乘法
  15. 苹果或将采用高通屏下指纹方案,5GiPhone基带由三星、高通共同提供...
  16. 002柿饼派GUI模组学习之AnimatedImage控件调试
  17. Elasticsearch别名(aliases)使用
  18. 港科夜闻|香港科大海洋科学系主任兼讲座教授钱培元:成立产业推广部抢商机...
  19. ja_charity模板研究_contin_1
  20. 常见分布式算法的介绍

热门文章

  1. openssl生成证书,并解决浏览器不信任问题
  2. 数组中哪些常用方法会修改原数组
  3. 怎样彻底删除微信记录,不被别人再恢复?涨姿势
  4. 少侠,留步,图片预览术
  5. 备考除了PDF编辑,还需要迅读PDF大师哪些神仙功能?
  6. 2345安全卫士使用分析报告
  7. Splash界面使用动画
  8. 买台式计算机看属性,如何查看台式电脑配置
  9. 南阳理工学院计算机的课程,2017春大学计算机(南阳理工学院)
  10. Capital One应用区块链协同认证系统专利