begin
min:
=d[i,1];t:
=i;
end;
find_min:
=t;
end;
procedurechange(t:
integer);
vari:
integer;
begin
fori:
=1tondo
ifnotp[i]and(map[t,i]>0)
and(d[i,1]=0)or(d[i,1]>d[t,1]+map[t,i])then
begind[i,1]:
=d[t,1]+map[t,i];d[i,2]:
=t;end;
end;
proceduredijkstra;
vari,j,t:
integer;
begin
p[1]:
=true;t:
=1;
repeat
change(t);
t:
=find_min;
p[t]:
=true;
untilp[n];
end;
procedureprint;
vari,t:
integer;
r:
array[1..max]ofinteger;
begin
t:
=1;r[1]:
=6;
whiled[r[t],2]>0do
begin
r[t+1]:
=d[r[t],2];inc(t);
end;
writeln('FromV1toV6');
fori:
=tdownto2do
write('V',r[i],'->');
writeln('V',r[1]);
writeln('Min=',d[6,1]);
end;
begin
clrscr;
init;
dijkstra;
print;
end.
练习一、
1、拓扑排序。
有N个士兵(1<=N<=26),依次编号为A,B,...,Z。
队列训练时,指挥官要把士兵从高到矮依次排成一行,但现在指挥官不能直接获得每个人的身高信息,只能获得"P1比P2高"这样的比较结果,记为"P1>P2",如"A>B"表示A比B高。
现从文本文件读入比较结果的信息,每个比较结果在文本文件中占一行。
编程输出一种符合条件的排队方案。
若输入的数据无解,则打印"NOANSWER!
"。
例如:
若输入为:
A>B
B>D
F>D
则一种正确的输出为:
ABFD
分析:
(1)由局部可比信息求得全局可比信息就是拓扑排序。
(2)局部信息可以用一个有向图表示。
如A>B,则在加一条由点A指向点B的有向线。
那么上例可以用右图表示出来。
(3)拓扑排序的方法:
(a)从图中选一个无前驱的点输出,同时删去由该点出发的所有的有向线;
(b)重复a,直至不能进行为止。
此时若图中还有点未输出,则问题无解;否则,输出的序列即为一可行方案。
注意:
在步骤(3)的b中,如果图中还有点未输出,说明图中有一个回路(即环)。
这在拓扑排序中是矛盾的。
比方说有如右图所示的一个环,其表示出来关于身高的信息是:
A>B,B>C,C>A,这显然是矛盾的,因此无解。
解:
略
2、地图四色:
用不超过四种的颜色给一个地图染色,使得相邻的两个地区所着的颜色各不相同。
3、最小部分树。
有一个城市分为N个区,现要在各区之间铺设有线电视线路。
任意两个区之间铺设线路的费用如下图所示,其中图的顶点表示各个区,线旁的数字表示铺设该条线路的费用。
要求设计一个费用最省的铺线方案使得每一个区均能收看到有线电视
分析:
(1)这个问题实际上是求图的最小部分树。
因为每一个区均能收看到有线电视,所以该图是连通的;又因为要求费用最省,所以该图无圈。
(2)求图的最小部分树常用Prim算法(也称加边法)和Kurskal算法(也称破圈法)
这里介绍的是Prim算法。
具体操作如下:
(a)去掉图中所有的线,只留下顶点;
(b)从图中任意选出一个点加入集合S1,余下的点划入集合S2;
(c)从所有连接集合S1与S2的点的线中选一条最短的加入图中,并将该线所连的集合S2中的点从集合S2中删去,加入集合S1中;
(d)重复步骤c,直至往图中加入N-1条边(N为顶点的个数)。
4、一笔画:
编一个程序对给定的图进行一笔画。
分析:
图的一笔画是指从图的某一个顶点出发,经过图中所有的边一次且仅一次。
现由文本文件读入一个图的邻接矩阵,判断该图能否一笔画,若能,则给出一笔画的方法。
分析:
一笔画是图论中研究得比较早的一个问题,一个图能够一笔画的条件是:
(1)该图是一个连通图;
(2)该图至多有2个度为奇数的点。
这里所说的"度"是指与一个点相连的边的数目,如果边的条数是奇数,则该点的度是奇数,否则是偶数。
在一笔画问题中,如果连通图所有的点的度均为偶数,则一笔画时可以从任意一点出发,最后又能回到起点。
如果有两个点的度为奇数,则一笔画时,一定是从一个奇数度的点出发,最后到达另一个奇数度的点。
此外,在连通图中,奇数度的点总是成对出现的。
一笔画所经过的路线又叫欧拉路(如果是回路的话,也叫欧拉回路)。
找欧拉路(或回路)可以用Fleury算法,如下:
(1)找一个出发点P(如果图中有两个奇数度的点话,任取其一)。
(2)找一条与P相连的边,伸展欧拉路(选边的时候应注意,最后再选取断边;断边是:
当去掉该边后使得图不连通的边)。
(3)将选出的边所连的另一个点取代P,去掉该边,重复
(2),直至经过所有的边。
5、哈密尔顿问题。
哈密尔顿问题是指在一个图中找出这样的一条路:
从一个图的顶点出发,经过图中所有顶点一次且仅一次。
象这样的路称为哈密尔顿路。
现由文本文件读入一个图的邻接表,判断该图是否有哈密尔顿路,若有则输出。
6、图的关节点。
如果从一个连通图中删去某点V,使得该图不连通,那么V点就称为该图的一个关节点。
现从文本文件中读入一个图的邻接矩阵,试编程找出该图所有的关节点。
有一集团公司下有N个子公司,各子公司由公路连接,现要在N个子公司中选一个出来成立总装车间,装配各子公司送来的部件,且使得各子公司到总装车间的路程总和最小。
第二节 动态规划
动态规划是近来发展较快的一种组合算法,是运筹学的一个分支,是解决多阶段决策过程最优化的一种数学方法。
我们可以用它来解决最优路径问题,资源分配问题,生产调度问题,库存问题,装载问题,排序问题,设备更新问题,生产过程最优控制问题等等。
在生产和科学实验当中,有一类活动的过程,可将它分成若干个阶段,在它的每个阶段要作出决策,从而使全局达到最优。
当各个阶段决策确定后,就组成一个决策序列,因而也就决定了整个过程的一条活动路线。
这种把一个过程看作一个前后相关具有链状结构的多阶段过程就称为多阶段决策过程。
所谓动态是指在多阶段决策问题中,各个阶段采取的决策,一般来说是与时间有关的,决策依赖于当前的状态,又随即引起状态的转移,一个决策序列就是在变化的状态中产生,故有"动态"的含义。
下面,我们结合最短路径问题来介绍动态规划的基本思想。
求下图中点O到点U的最短距离(假设只许往上和往右走)。
从点O到点U,可以按经过的路径,分成七个阶段,分别为:
O->AB->CDE->FGHJ->
KLMN->PQR->ST->U。
最短路径有一个重要特性:
如果点O经过点H到达点U是一条最短路径,则在这条最优路径上由点H出发到达点U的子路径,是由点H出发到达点U所有可能选择的不同路径的最短路径(证明略)。
根据这一特点,寻找最短路径的时候,可以从最后一段开始,用由后向前逐段递推的方法,求出个点到点U的最短路径。
如若考虑到从点O到点U的最短路径,也是该路径上个点到点的最短路径,令O点到U点的最短距离为dO,A点到U点的最短距离为dA,...,故有:
dO=min{2+dA,1+dB},
dA=min{3+dC,2+dD},
dB=min{2+dD,3+dE},
................
dQ=min{5+dT,2+dS}.
下面按照动态规划的方法,将上例从最后一段开始计算,由后向前逐步递推移至O点。
计算步骤如下:
阶段7:
从S点或T点到达U点,这时各自只有一种选择,故:
dS=2;dT=3;
阶段6:
出发点有P,Q,R三个,其中Q点到达U点有两种选择,或是经过S点,或是经过T点,故:
dQ=min{2+dS,5+dT}=min{4,8}=4;
dP=min{1+dS}=min{3}=3;
dR=min{3+dT}=min{6}=6;
阶段5:
出发点有K,L,M,N四个,同理有:
dK=min{3+dP}=min{6}=6;
dL=min{2+dP,4+dq}=min{5,8}=5;
dM=min{2+dQ,4+dR}=min{6,10}=6;
dN=min{4+dR}=min{10}=10;
阶段4:
出发点有F,G,H,J四个,同理有:
dF=min{2+dK}=min{8}=8;
dG=min{1+dK,3+dL}=min{7,8}=7;
dH=min{1+dL,1+d}=min{6,7}=6;
dJ=min{3+dM,3+dN}=min{9,13}=9;
阶段3:
出发点有C,D,E三个,同理有:
dC=min{2+dF,2+dG}=min{10,9}=9;
dD=min{4+dG,2+dH}=min{11,8}=8;
dE=min{1+dH,2+dJ}=min{7,11}=7;
阶段2:
出发点有A,B两个,同理有:
dA=min{3+dC,2+dD}=min{12,10}=10;
dB=min{2+dD,3+dE}=min{10,10}=10;
阶段1:
出发点是O,同理有:
dO=min{2+dA,1+dB}=min{12,11}=11.
由此得到全过程的最短路径是11,并且可以由以上推导过程反推得最短的路线是:
O->B->D->H->L->P->S->U;或O->B->E->H->L->P->S->U。
从上可以知道,能应用动态规划解决的问题,必须满足最优性原则,动态规划的关键在于正确的写出基本的递推关系式和恰当的边界条件。
它需要把问题的过程化成几个互相联系的阶段,恰当的选取状态变量和决策变量及定义最优值函数,从而把一个大问题化成一族同类型的子问题,然后逐个求解。
即从边界条件开始,逐段递推寻优,在每一个子问题的求解中,都利用到前面的子问题的最优化结果,依次进行,最后一个子问题的最优解,就是整个问题的最优解。
例一、数字三角形:
下图给出了一个数字三角形.请编一个程序计算从顶至底的某处的一条路径,使得该路径所经过的数字的总和最大。
对于路径规定如下:
(1)每一步可沿左斜线向下走或右斜线向下走;⑦
(2)1<三角形的行数<=100;③8
(3)三角形中的数字为整数0,1,...,99;⑧10
输入数据:
由文件INPUT.TXT中首先读出的2⑦44
是三角形的行数。
在例子中INPUT.TXT表示如下:
4⑤265
5
7
38
810
2744
45265
输出最大的总和。
如上例为:
30(其路径如图圈的数字)。
分析:
(1)假设最优路径(即总和最大)为⑦→③→⑧→⑦→⑤,则子路径⑦→③→⑧→⑦必定是从初始点⑦到中间点⑦的所有路径中最优的,否则,如果从初始点⑦到中间点⑦还有另一条的路径更优,假设为⑦→a1→a2→⑦,则新路径⑦→a1→a2→⑦→⑤则优于原来假设的最优路径⑦→③→⑧→⑦→⑤,与假设矛盾。
从以上反证法可以清楚地知道:
数字三角形问题满足动态规划的最优性原则,可以利用动态规划求解。
(2)采用顺推法:
记第i行第j列的数字为a(i,j),从初始点到a(i,j)的最大总和记为f(i,j);则应有第一层上的数字的a(1,1)的最大总和为它本身,即:
f(1,1)=a(1,1);
以下各层按如下方法递推:
f(i,j)=a(i,j)+max{f(i-1,j-1),f(i-1,j)}
(3)用以上方法递推计算完最后一层,最后一中寻最大值即为本题的解.
解:
Pascal程序:
Programlt10_2_1;
usescrt;
constmax=100;
varn:
integer;
a:
array[0..max,0..max]oflongint;
procedurework;
varf:
text;
i,j:
integer;
begin
assign(f,'input.txt');
reset(f);
readln(f,n);
fillchar(a,sizeof(a),0);
fori:
=1tondo
forj:
=1toido
begin
read(f,a[i,j]);
ifa[i-1,j-1]>a[i-1,j]then
a[i,j]:
=a[i,j]+a[i-1,j-1]
elsea[i,j]:
=a[i,j]+a[i-1,j];
end;
close(f);
end;
procedureprint;
varmax:
longint;
i:
integer;
begin
max:
=0;
fori:
=1tondo
ifa[n,i]>maxthenmax:
=a[n,i];
writeln('Max=',max);
end;
begin
clrscr;
work;print;
end.
习题二:
1、某工业生产部门根据国家计划的安排,拟将某种高效率的五台机器,分配给所属的A,B,C三个工厂,各工厂若获得这种机器后,可以为国家盈利如下表,问:
这五台机器如何分配给各工厂,才能使国家盈利最大?
单位:
万元
P
S
A
B
C
0
0
0
0
1
3
5
4
2
7
10
6
3
9
11
11
4
12
11
12
5
13
11
12
其中:
p为盈利,s为机器台数。
2、己知:
f(x)=x1^2+2x2^2+x3^2-2x1-4x2-2x3
x1+x2+x3=3且x1,x2,x3均为非负整数。
求f(x)的最小值。
3、N块银币中有一块不合格,不合格的银币较正常为重,现用一天平找出不合格的来,要求最坏情况不用天平的次数最少。
4、某一印刷厂有6项加工任务,对印刷车间和装订车间所需时间见下表:
任务
J1
J2
J3
J4
J5
J6
印刷车间
3
12
5
2
9
11
装订车间
8
10
9
6
3
1
时间单位:
天
完成每项任务都要先去印刷车间印刷,再到装订车间装订。
问怎样安排这6项加工任务的加工工序,使得加工总工时最少。
5、有一个由数字1,2,...,9组成的数字串(长度不超过200),问如何M(1<=M<=20)个加号插入这个数字串中,使得所形成的算术表达式的值最小。
注意:
(1)加号不能加在数字串的最前面或最末尾,也不应有两个或两个以上的加号相邻;
(2)M保证小于数字串的长度。
例如:
数字串79846,若需加入两个加号,则最佳方案是79+8+46,算术表达式的值是133。
输入格式:
从键盘读入输入文件名。