【数学建模】常用模型算法及MATLAB代码汇总

缺乏、安全感 2023-02-16 04:11 126阅读 0赞

#

    • 一、蒙特卡洛算法
    • 二、数据拟合
    • 三、数据插值
    • 四、图论
      • 1、最短路问题
        • (1)Dijkstra算法
        • (2)Floyd算法

一、蒙特卡洛算法

1、定义

蒙特卡洛算法是以概率和统计的理论、方法为基础的一种数值计算方法,将所求解的问题同一定的概率模型相联系,用计算机实现统计模拟或抽样,以获得问题的近似解,故又称随机抽样法或统计实验法。

2、适用范围

可以较好的解决多重积分计算、微分方程求解、积分方程求解、特征值计算和非线性方程组求解等高难度和复杂的数学计算问题。

3、特点

蒙特卡洛算法可以应用在很多场合,但求的是近似解,在模拟样本越大的情况下,越接近于真实值,单样本数增加会带来计算量的大幅上升。对于一些简单问题来说,蒙特卡洛是个笨办法,但对于许多问题来说,它往往是个有效,有时甚至是唯一可行的方法。

4、举例

y = x^2 ,y = 12 - x 与 X 轴在第一象限与 X 轴围成一个曲边三角形。设计一个随机试验,求该图形的近似值。

(1)作图
在这里插入图片描述
Code:

  1. %作图
  2. x = 0:0.25:12;
  3. y1 = x.^2;
  4. y2 = 12 - x;
  5. plot(x, y1, x, y2)
  6. xlabel('x');ylabel('y');
  7. %产生图例
  8. legend('y1=x^2', 'y2=12-x');
  9. title('蒙特卡洛算法');
  10. %图中x轴和y轴的范围,中括号前面是y轴范围,中括号后面是x轴范围
  11. axis([0 15 0 15]);
  12. text(3, 9, '交点');
  13. %加上网格线
  14. grid on

(2)设计的随机试验的思想:在矩形区域[0,12]*[0.9]上产生服从均与分布的10^7个随机点,统计随机点落在曲边三角形内的个数,则曲边三角形的面积近似于上述矩形的面积乘以频率。

Code:

  1. %蒙特卡洛算法的具体实现
  2. %产生一个110000000列的矩阵,矩阵中每个数是从012之间随机取
  3. x = unifrnd(0, 12, [1, 10000000]);
  4. y = unifrnd(0, 9, [1, 10000000]);
  5. frequency = sum(y<x.^2&x<=3)+ sum(y<12-x&x>=3);
  6. area = 12*9*frequency/10^7;
  7. disp(area);

所求近似值:
在这里插入图片描述

参考博客:https://blog.csdn.net/u013414501/article/details/50478898

二、数据拟合

1、定义

已知有限个数据点,求近似函数,可不过已知数据点,只要求在某种意义下它在这些点上的总偏差最小,从而能较好的反应数据的整体变化趋势。

2、常用方法

  • 一般采用最小二乘法。
  • 拟合的实现分为 MATLAB 和 excel 实现。MATLAB 的实现就是 polyfit 函数,主要是多项式拟合。

3、举例

(1) 数据如下:

  1. 序号 x y z
  2. 1 426.6279 0.066 2.897867
  3. 2 465.325 0.123 1.621569
  4. 3 504.0792 0.102 2.429227
  5. 4 419.1864 0.057 3.50554
  6. 5 464.2019 0.103 1.153921
  7. 6 383.0993 0.057 2.297169
  8. 7 416.3144 0.049 3.058917
  9. 8 464.2762 0.088 1.369858
  10. 9 453.0949 0.09 3.028741
  11. 10 376.9057 0.049 4.047241
  12. 11 409.0494 0.045 4.838143
  13. 12 449.4363 0.079 4.120973
  14. 13 372.1432 0.041 3.604795
  15. 14 389.0911 0.085 2.048922
  16. 15 446.7059 0.057 3.372603
  17. 16 347.5848 0.03 4.643016
  18. 17 379.3764 0.041 4.74171
  19. 18 453.6719 0.082 1.841441
  20. 19 388.1694 0.051 2.293532
  21. 20 444.9446 0.076 3.541803
  22. 21 437.4085 0.056 3.984765
  23. 22 408.9602 0.078 2.291967
  24. 23 393.7606 0.059 2.910391
  25. 24 443.1192 0.063 3.080523
  26. 25 514.1963 0.153 1.314749
  27. 26 377.8119 0.041 3.967584
  28. 27 421.5248 0.063 3.005718
  29. 28 421.5248 0.063 3.005718
  30. 29 421.5248 0.063 3.005718
  31. 30 421.5248 0.063 3.005718
  32. 31 421.5248 0.063 3.005718
  33. 32 421.5248 0.063 3.005718
  34. 33 421.5248 0.063 3.005718
  35. 34 421.5248 0.063 3.005718
  36. 35 421.5248 0.063 3.005718
  37. 36 421.5248 0.063 3.005718
  38. 37 416.1229 0.111 1.281646
  39. 38 369.019 0.04 2.861201
  40. 39 362.2008 0.036 3.060995
  41. 40 417.1425 0.038 3.69532

(2) 方法一:使用MATLAB编写代码

  1. %读取表格
  2. A = xlsread('E:\表格\1.xls', 'Sheet1', 'A1:AN2');
  3. B = A;
  4. [I, J] = size(B);
  5. %数据拟合
  6. %x为矩阵的第一行,y为矩阵的第二行
  7. x = A(1,:);
  8. y = A(2,:);
  9. %polyfitmatlab中的拟合函数,第一个参数是数据的横坐标
  10. %第二个参数是数据的纵坐标,第三个参数是多项式的最高阶数
  11. %返回值p中包含n+1个多项式系数
  12. p = polyfit(x, y, 2);
  13. disp(p);
  14. %下面是作图的代码
  15. x1 = 300:10:600;
  16. %polyvalmatlab中的求值函数,求x1对应的函数值y1
  17. y1 = polyval(p,x1);
  18. plot(x,y,'*r',x1,y1,'-b');
  19. %plot(x,'DisplayName','x','YDataSource','x');
  20. %figure(gcf);

(3) 方法三:使用matlab的图形化拟合包(推荐)

  • 将数据导入工作区并通过cftool命令打开matlab的图形化拟合包
    在这里插入图片描述
  • 选择x、y变量
    在这里插入图片描述
  • 选择拟合方式和最高项次数
    在这里插入图片描述
  • 得到拟合结果
    在这里插入图片描述

使用图形化拟合工具不仅简单快捷,还可以使用多种拟合方式,寻找到最好的拟合曲线。

三、数据插值

1、定义

  • 在离散数据的基础上补插连续函数,使得这条连续曲线通过给定的全部离散数据点。即求过已知有限个数据点的近似函数。
  • 从定义上看,插值和拟合有一定的相似度,但插值要求近似函数通过给定的所有离散数据,而拟合并不要求这样,只要近似函数能较好的反映数据变化的趋势即可(近似含义不同),当测量值是准确的,没有误差时,一般用插值;当测量值与真实值有误差时,一般用数据拟合。

2、作用

插值是离散函数逼近的重要方法,利用它可通过函数在有限个点处的取值情况,估算出函数在其他点处的近似值。

3、举例

  1. %yearsservicewage是原始数据
  2. years = 1950:10:1990;
  3. service = 10:10:30;
  4. wage = [ 150.697 199.592 187.625 179.323 195.072; 250.287 203.212 179.092 322.767 226.505;153.706 426.730 249.633 120.281 598.243];
  5. [X, Y] = meshgrid(years, service);
  6. % % 三维曲线
  7. % plot3(X, Y, wage)
  8. % 三维曲面
  9. figure
  10. surf(X, Y, wage)
  11. %interp2matlab中的二维插值函数,前两个参数是已知位置,后两个是未知位置,w是未知位置的插值结果
  12. w = interp2(service,years,wage,15,1975);

在这里插入图片描述

可参考:数学建模常用模型02 :插值与拟合

四、图论

1、最短路问题

最短路问题就是选择一条距离最短的路线。

例如:一名货柜车司机奉命在最短的时间内将一车货物从甲地运往乙地。从甲地到乙地的公路网纵横交错,因此有多种行车路线,这名司机应选择哪条线路呢?假设货柜车的运行速度是恒定的,那么这一问题相当于需要找到一条从甲地到乙地的最短路。(Dijkstra算法)

具体介绍见这里:最短路径—Dijkstra算法和Floyd算法

(1)Dijkstra算法

先给出一个无向图
在这里插入图片描述

用Dijkstra算法找出以A为起点的单源最短路径步骤如下
在这里插入图片描述

代码模板:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cmath>
  5. #include<cstring>
  6. #include<algorithm>
  7. #include<vector>
  8. #include<fstream>
  9. using namespace std;
  10. const int maxnum = 100;
  11. const int maxint = 2147483647;
  12. int dist[maxnum]; // 表示当前点到源点的最短路径长度
  13. int prev[maxnum]; // 记录当前点的前一个结点
  14. int c[maxnum][maxnum]; // 记录图的两点间路径长度
  15. int n, line; // n表示图的结点数,line表示路径个数
  16. void Dijkstra(int n, int v, int *dist, int *prev, int c[maxnum][maxnum])
  17. {
  18. bool s[maxnum]; // 判断是否已存入该点到S集合中
  19. for(int i=1; i<=n; ++i)
  20. {
  21. dist[i] = c[v][i];
  22. s[i] = 0; // 初始都未用过该点
  23. if(dist[i] == maxint)
  24. prev[i] = 0;
  25. else
  26. prev[i] = v;
  27. }
  28. dist[v] = 0;
  29. s[v] = 1;
  30. // 依次将未放入S集合的结点中,取dist[]最小值的结点,放入结合S中
  31. // 一旦S包含了所有V中顶点,dist就记录了从源点到所有其他顶点之间的最短路径长度
  32. for(int i=2; i<=n; ++i)
  33. {
  34. int tmp = maxint;
  35. int u = v;
  36. // 找出当前未使用的点j的dist[j]最小值
  37. for(int j=1; j<=n; ++j)
  38. if((!s[j]) && dist[j]<tmp)
  39. {
  40. u = j; // u保存当前邻接点中距离最小的点的号码
  41. tmp = dist[j];
  42. }
  43. s[u] = 1; // 表示u点已存入S集合中
  44. // 更新dist
  45. for(int j=1; j<=n; ++j)
  46. if((!s[j]) && c[u][j]<maxint)
  47. {
  48. int newdist = dist[u] + c[u][j];
  49. if(newdist < dist[j])
  50. {
  51. dist[j] = newdist;
  52. prev[j] = u;
  53. }
  54. }
  55. }
  56. }
  57. void searchPath(int *prev,int v, int u)
  58. {
  59. int que[maxnum];
  60. int tot = 1;
  61. que[tot] = u;
  62. tot++;
  63. int tmp = prev[u];
  64. while(tmp != v)
  65. {
  66. que[tot] = tmp;
  67. tot++;
  68. tmp = prev[tmp];
  69. }
  70. que[tot] = v;
  71. for(int i=tot; i>=1; --i)
  72. if(i != 1)
  73. cout << que[i] << " -> ";
  74. else
  75. cout << que[i] << endl;
  76. }
  77. int main()
  78. {
  79. //freopen("input.txt", "r", stdin);
  80. // 各数组都从下标1开始
  81. // 输入结点数
  82. cin >> n;
  83. // 输入路径数
  84. cin >> line;
  85. int p, q, len; // 输入p, q两点及其路径长度
  86. // 初始化c[][]为maxint
  87. for(int i=1; i<=n; ++i)
  88. for(int j=1; j<=n; ++j)
  89. c[i][j] = maxint;
  90. for(int i=1; i<=line; ++i)
  91. {
  92. cin >> p >> q >> len;
  93. if(len < c[p][q]) // 有重边
  94. {
  95. c[p][q] = len; // p指向q
  96. c[q][p] = len; // q指向p,这样表示无向图
  97. }
  98. }
  99. for(int i=1; i<=n; ++i)
  100. dist[i] = maxint;
  101. for(int i=1; i<=n; ++i)
  102. {
  103. for(int j=1; j<=n; ++j)
  104. printf("%-16d", c[i][j]);
  105. printf("\n");
  106. }
  107. Dijkstra(n, 1, dist, prev, c); //仅调用函数求出了源点到其他点的距离 改法:Dijkstra(n, x, dist, prev, c); 其中x=1,2,3,4,...,n
  108. // for(int i=1; i<=n; ++i) //dist存储了源点到其他点的距离情况
  109. // {
  110. // printf("%-16d", dist[i]);
  111. // }
  112. printf("\n");
  113. // 最短路径长度
  114. cout << "源点到最后一个顶点的最短路径长度: " << dist[n] << endl;
  115. // 路径
  116. cout << "源点到最后一个顶点的路径为: ";
  117. searchPath(prev, 1, n);
  118. return 0;
  119. }
  120. /* 输入数据: 5 7 1 2 10 1 4 30 1 5 100 2 3 50 3 5 10 4 3 20 4 5 60 输出数据: 999999 10 999999 30 100 10 999999 50 999999 999999 999999 50 999999 20 10 30 999999 20 999999 60 100 999999 10 60 999999 源点到最后一个顶点的最短路径长度: 60 源点到最后一个顶点的路径为: 1 -> 4 -> 3 -> 5 */

(2)Floyd算法

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cmath>
  5. #include<cstring>
  6. #include<algorithm>
  7. #include<vector>
  8. #include<fstream>
  9. using namespace std;
  10. //设点与点之间的距离均为double型
  11. double INFTY=2147483647;
  12. const int MAX=1000;
  13. double dis[MAX][MAX];
  14. double a[MAX][MAX];
  15. int path[MAX][MAX];
  16. int n,m; //结点个数
  17. void Floyd()
  18. {
  19. int i,j,k;
  20. for(i=1;i<=n;i++)
  21. {
  22. for(j=1;j<=n;j++)
  23. {
  24. dis[i][j]=a[i][j];
  25. if(i!=j&&a[i][j]<INFTY)
  26. {
  27. path[i][j]=i;
  28. }
  29. else
  30. path[i][j]=-1;
  31. }
  32. }
  33. for(k=1;k<=n;k++)
  34. {
  35. for(i=1;i<=n;i++)
  36. {
  37. for(j=1;j<=n;j++)
  38. {
  39. if(dis[i][k]+dis[k][j]<dis[i][j])
  40. {
  41. dis[i][j]=dis[i][k]+dis[k][j];
  42. path[i][j]=path[k][j];
  43. }
  44. }
  45. }
  46. }
  47. }
  48. int main()
  49. {
  50. //freopen("datain.txt","r",stdin);
  51. int beg,enda;
  52. double dist;
  53. scanf("%d%d",&n,&m);
  54. for(int i=1;i<=n;i++)
  55. {
  56. for(int j=1;j<=n;j++)
  57. {
  58. if(i==j)
  59. a[i][j]=0;
  60. else
  61. a[i][j]=INFTY;
  62. }
  63. }
  64. for(int i=1;i<=m;i++)
  65. {
  66. scanf("%d%d%lf",&beg,&enda,&dist);
  67. a[beg][enda]=a[enda][beg]=dist;
  68. }
  69. Floyd();
  70. for(int i=1;i<=n;i++)
  71. {
  72. for(int j=1;j<=n;j++)
  73. {
  74. printf("%-12lf",dis[i][j]);
  75. }
  76. printf("\n");
  77. }
  78. return 0;
  79. }

发表评论

表情:
评论列表 (有 0 条评论,126人围观)

还没有评论,来说两句吧...

相关阅读