数学模型学习报告21-01-18

图论模型

1.最短路程模型
2.TSP问题
3.最小生成树

最短路程模型

主要算法是Dijkstra算法(指定两点的最短线路,复杂度为o(n2))和Floyd算法(任意两点的最短路线,复杂度为o(n3))

给定网络N=(V,E,W) (顶点集合,边的集合,边的权值),求 i 点到 j 点的最短路线。

Dijkstra算法:
  1. 给出初始点集合P={ i },剩余点集合Q={1,2,3……n}-P,i点到各点直接距离Ur=wir(r=1,2,3…n)
  2. 在Q中寻找到i点距离最小的点k,使得Uk=min{ Ur},并置P∪{k} ➡P,Q-{k}➡Q (即把k点从集合Q转移到集合P)
  3. 对Q中每一个r,如果Uk+wkr<Ur,则Uk+wkr➡Ur,然后返回第二步直到找到 j 点为止
    【此算法经过n-1次结束,在整个算法过程中,第二步最多要做(n-1)(n-2)/2次比较,因此计算量为o(n2)阶】
Floyd算法:
  1. 根据已知的部分节点之间的连续信息,建立初始距离矩阵B(i,j),其中把没有给出距离的赋予一个充分大的数值(这样就相当于“此路不通”,不会妨碍接下来的计算),以便于更新。(i,j=1,2,3…n)
  2. 进行迭代计算,对任意两点( i, j ),若存在k,使B(i,k)+B(k,j)<B(i,j),则更新B(i,j)=B(i,k)+B(k,j).
for k=1:n
 for i=1:n             %只要三个循环的Floyd就是屑
  for j=1:n            %然而我从未想到过,我更屑
   t=B(i,k)+B(k,j)
   if t<B(i,j) B(i,j)=t;end
  end
 end
end

在运行之前,要复制一个二维数组,表示每两点之间的距离
例如:

点1点2点3
点102310000
点223015
点310000150

其中点1和点3没有直接连接,故用一个充分大值

n=总点数
A=zeros(n,n)
for i=1:n
 for j=1:n
  if(i==j) A(i,j)=0;
  else A(i,j)=10000;  %首先全部赋值一个充分大值
  end
 end
end
%然后一个个赋值(此处省略)
%接下来使矩阵对称
for j=1:n
 for i=1:j-1
  A(j,i)=A(i,j);
 end
end

对于结果的输出:

fid=fopen('distance.txt','w');
 for i=1:n
  for j=1:n
   fprintf(fid,'%4d',B(i,j));
  end
  fprintf(fid,'\n');
 end
fclose(fid)
TSP问题

常用的方法有近邻法,贪心算法,最近插入法,模拟退火算法,遗传算法

设城市之间距离用矩阵d表示,dij表示城市 i 与城市 j 的距离(若没有,则用Floyd算)。同时设0-1矩阵X用来表示经过的各城市之间的路线。
在这里插入图片描述考虑到到达每个城市之后能且只能去往另一个城市,则

在这里插入图片描述同时会出现一种子圈问题:
以55的矩阵为例
在这里插入图片描述为避免产生子圈应增加约束:
ui-uj+n
xij≤n-1 (1<i≠j≤n)

在这里给出简单的解释:
如果 i 点,k点和 j 点形成了子圈,那么就会有
xij=1, xjk=1, xki=1
分别带入此式,则有
ui-uj≤-1,uj-uk≤-1,uk-ui≤-1
此三式相加,则会有0≤-3,矛盾
区区人类居然可以想出如此绝妙的方法

因此总的线性规划模型就是:
在这里插入图片描述
可采用lingo进行编程:

MODEL:
SETS:
city/1..10/:u;        !以十个城市为例
link(city,city):d,x;
ENDSETS
DATA
d=(一张10*10的二维数组);
@text()=@writefor(link(i,j)|x(i,j)#GT#0:'x(',i,',',j,')=',x(i,j))
ENDDATA
MIN=@SUM(link:d*x);
@for(city(j):@sum(city(i)|j#ne#i:x(i,j))=1);
@for(city(i):@sum(city(j)|j#ne#i:x(i,j))=1);
@for(link(i,j)|i#ne#j#and#i#gt#1:u(i)-u(j)+10*x(i,j)<=9);
@for(link:@BIN(x));
End

【注意,如果问题并不要求要返回到出发点,我们可以考虑引入一个虚拟点n+1(类似画辅助线做几何题)。此点与各个地点距离都为0,这样可以使链和圈等价】(这真的是人类的脑子想出来的吗)

lingo编程规则
lingo编程用四部分组成

  1. 定义集合
sets:          !以sets开头,endsets结尾,这两行不加引号
name/member_list/:attribute,etc;      !定义一个原始集合
name(set1,set2,etc):attribute,etc;       !定义一个导出集合
endsets

!例
Person/1..10/:A;  !这是一个有十个元素的集合,名字是person,存在A中
Task/1..12/:B;
Link(Person,Task):x;    !这是一个10*12二维数组,名字叫link
  1. 目标与约束
    在此部分写目标函数和约束条件
  2. 数据部分
DATA:
attribute=value_list;
ENDDATA
  1. 初始化部分
    对集合的属性(数组)定义初值。
INIT:
attribute=value_list;
ENDINIT

对内部函数的引用
以@打头

@ABS(x)绝对值
@cos(x)余弦值
@EXP(x)ex
@FLOOR(x)向0靠近返回整数部分
@LGM(x)返回Γ函数自然数对数值
@LOG(x)x的自然对数值
@SIGN(x)返回x的符号值,x<0,返回-1,x大于0,返回1
@SMAX(x1,x2…xn)返回最大值

集合函数的操作
在这里插入图片描述

@FOR(set_name:constraint_expressions)    !对集合set_name的每个元素独立地生成约束
@MAX(set_name:expression)     !返回集合上表达式的最大值
@SUM(set_name:expression:expression)     !求和
@SIZE(set_name)               !返回元素的个数
@IN(set_name,set_element)     !如果集合set_name中包含元素set_element,返回1,否则返回0

逻辑语

#AND#
#OR#
#NOT#
#EQ#=
#NE#
#GT#
#GE#
#LT#
#LE#

变量界定

@BND(L,X,U)L≤X≤U
@BIN(x)限制x为0或1
@FREE(x)取消对x的符号限制
@GIN(x)限制x为整数值
最小生成树

连通且不含圈的无向图,常用T表示。
树中的边称为枝,树中度为1(只有一只枝与其相接)的点为叶
在这里插入图片描述若T是包含图G的全部顶点的子图,它又是树,则称T是G的生成树。
如果设T=(V,E)是赋权图G=(V,E)的一棵生成树,则称T中全部枝上的权数之和为生成树的权,记为w(T),即w(T)=Σw(e),如果T的权w(T)是G中所有生成树中最小者,则它为最小生成树,即w(T*)=Σmin{w(T)}
【赋权图:每条边上都有一个非负实数对应的图,此实数为权。例如道路图,每条路有一个对应的长度数值,此数值为权】
求解有
kruskal避圈算法和Prim破圈算法
在lingo中
设无向图有n个顶点,其赋权图的邻接矩阵为dn*n,dij表示边 i j的权,令dii=0。
现求根节点1到各节点生成的最小生成树。
在这里插入图片描述

model:
sets:
point/1..n/:u;
link(point,point):d,x;
endsets
data:
d=(n*n的表);
@text()=@writefor(link(i,j)|x(i,j)#GT#0:'x(',i,',',j,')=',x(i,j))
enddata
min=@sum(link(i,j)|i#ne#j:d(i,j)*x(i,j));
n=@size(piont);
@sum(point(j)|j#gt#1:x(1,j))>=1;
@for(point(i)|#ne#1:@sum(point(j)|j#ne#i:x(j,i))=1);
@for(link(i,j):@bin(x(i,j)));
@for(link(i,j)|i#ne#j:u(i)-u(j)+n*x(i,j)<=n-1);
end
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值