数学建模题型与知识框架总览
题型:
1.数据处理 2.关联与分析 3.分类与判别 4.评价与决策 5.预测与预报 6.优化与控制
优化与控制:
通过数学模型和算法,寻找最优解的过程
知识框架:
1.线性规划 2.整数规划 3.动态规划 4.非线性规划 5.多目标规划 6.启发式算法
动态规划
判断
题型较多但问题一般是有多阶段决策过程的
类型
1、求方法数:达到某种目的的方法一共有几种
2、求最大最小:做到某事的方法中最xx的
3、判断存在性:某个事情是否可以做到
做法
1、确定状态:
因为问题一般都是有一个过程的,所以题目所描述的情景可以抽象为由一个状态转变到另一个状态一步一步走到最后的过程。
这一步就是要用某个形式表达状态,一般用数组,一般每个状态有几个量描述数组就有几维,而这个数组中值的意义自己根据题目规定。
2、确定状态转移方程
一个状态怎么转移到另一个状态的,根据状态表达的意义和题目描述的关系进行确认
3、初始化初始状态和边界情况
初始状态:在那么多状态中,总有一个状态是不用从别的转态转换过来的,一般是那种一眼可以看出的状态,自行初始化,然后就可以从他开始根据状态转移方程推出其他状态了。
边界情况:有些状态是无意义的,为了后续计算正确一般要自行初始化,后续做特殊处理
4、确定计算顺序
就是从已知状态一步一步推到结束状态的顺序,因为某些状态的计算需要先知道一些别的状态,所有需要考虑计算顺序的问题。
确定后用循环执行。
例子:
题目1
1、LintCode 炼码 - 更高效的学习体验! -----最大最小问题、存在性问题
给出不同面额的硬币以及一个总金额. 写一个方法来计算给出的总金额可以换取的最少的硬币数量. 如果已有硬币的任意组合均无法与总金额面额相等, 那么返回 -1
代码1
public class Solution {
/**
* @param coins: a list of integer
* @param amount: a total amount of money amount
* @return: the fewest number of coins that you need to make up
*/
public int coinChange(int[] A, int M) {
// write your code here
int [] f=new int[M+1];//1、确定状态:f[n]为总金额为n的最小钞票张数
int n=A.length;
f[0]=0;//3、初始化:当面额为0时,最小零张钞票足够
int i,j;
for(i=1;i<=M;++i){
//f[i]=+infty
f[i]=Integer.MAX_VALUE;
//2、循环实现状态转移方程:f[i]=min{f[i-A[0]]+1,f[i-A[1]+1,....,f[i-A[n-1]]+1}
//4、按照之前确定的顺序进行循环
for(j=0;j<n;j++){
if(i>=A[j]&&f[i-A[j]]!=Integer.MAX_VALUE){
f[i]=Math.min(f[i],f[i-A[j]]+1);
}
}
}
if(f[M]==Integer.MAX_VALUE){
f[M]=-1;
}
return f[M];
}
}
题目2
2、LintCode 炼码 - 更高效的学习体验! --------存在性问题
给出一个非负整数数组,你最初定位在数组的第一个位置。数组中的每个元素代表你在那个位置可以跳跃的最大长度。判断你是否能到达数组的最后一个位置。
代码2
public class Solution {
/**
* @param a: A list of integers
* @return: A boolean
*/
public boolean canJump(int[] A) {
// write your code here
int n=A.length;
boolean[] f=new boolean[n];//1、确定状态f[n]表示第n个位置能否跳到
f[0]=true;//3、初始化,第一个位置一定可以跳到,为true
//4、根据确定的计算顺序进行循环,要先知道前面位置能不能跳到才能推导后面位置,故从小往大
for(int j=1;j<n;++j){
f[j]=false;
//2、用循环实现状态转移方程第j个位置前的任意一个位置i若能跳到j,f[j]为true
for(int i=0;i<j;++i){
if(f[i]&&i+A[i]>=j){
f[j]=true;
break;
}
}
}
return f[n-1];
}
}
题目3
3、LintCode 炼码 - 更高效的学习体验! --------计算有几种方法问题
有一个机器人的位于一个 m×n 个网格左上角。机器人每一时刻只能向下或者向右移动一步。机器人试图达到网格的右下角。问有多少条不同的路径?
代码3
public class Solution {
/**
* @param m: positive integer (1 <= m <= 100)
* @param n: positive integer (1 <= n <= 100)
* @return: An integer
*/
public int uniquePaths(int m, int n) {
// write your code here
int [][] f=new int[m][n];//1、确定状态:f[n][m]表示第n行m列的位置有几种方法可以走到
int i,j;
for(i=0;i<m;++i){//4、根据计算顺序进行循环,应为要先知道上面、左边的方法才可推导后面的故从左到右,从上到下
for(j=0;j<n;++j){
if(i==0||j==0){//3、初始化,行或列为1的位置只有一种方法走到
f[i][j]=1;
}
else{//2、状态转移方程,走到f[i][j]的方法有f[i][j-1]加上f[i-1][j]种
f[i][j]=f[i][j-1]+f[i-1][j];
}
}
}
return f[m-1][n-1];
}
}
想法
1、第一步确定状态还是比较难的,一般可以从最后一步看问题可以转换成什么与前一步有关的问题,然后一步步倒推可以转换成怎样的子问题,而这个子问题中需要知道的东西是什么?这个要知道的东西一般就是状态代表的意义。
2、其实整个分析过程有点像递归,但用动态规划的写法顺序是从前到后推导的,递归是反复调用自身遍历每个路径直到终止。动态规划保存了中间结果,避免了重复计算,从而提高了效率。