图论实验三个案例单源最短路径问题1.1Dijkstra算法Dijkstra算法是解单源最短路径问题的一个贪心算法。其基本思想是,设置一个顶点集合S并不断地作贪心选择来扩充这个集合。一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知。设v是图中的一个顶点,记()lv为顶点v到源点v1的最短距离,,ijvvV,若(,)ijvvE,记iv到jv的权ijw。Dijkstra算法:①1{}Sv,1()0lv;1{}vVv,()lv,1i,1{}SVv;②S,停止,否则转③;③()min{(),(,)}jlvlvdvv,jvS,vS;④存在1iv,使1()min{()}ilvlv,vS;⑤1{}iSSv,1{}iSSv,1ii,转②;实际上,Dijkstra算法也是最优化原理的应用:如果121nnvvvv是从1v到nv的最短路径,则121nvvv也必然是从1v到1nv的最优路径。在下面的MATLAB实现代码中,我们用到了距离矩阵,矩阵第i行第j行元素表示顶点iv到jv的权ijw,若iv到jv无边,则realmaxijw,其中realmax是MATLAB常量,表示最大的实数(1.7977e+308)。functionre=Dijkstra(ma)%用Dijkstra算法求单源最短路径%输入参量ma是距离矩阵%输出参量是一个三行n列矩阵,每列表示顶点号及顶点到源的最短距离和前顶点n=size(ma,1);%得到距离矩阵的维数s=ones(1,n);s(1)=0;%标记集合S和S的补r=zeros(3,n);r(1,:)=1:n;r(2,2:end)=realmax;%初始化fori=2:n;%控制循环次数mm=realmax;forj=find(s==0);%集合S中的顶点fork=find(s==1);%集合S补中的顶点if(r(2,j)+ma(j,k)r(2,k))r(2,k)=r(2,j)+ma(j,k);r(3,k)=j;endif(mmr(2,k))mm=r(2,k);t=k;endendends(1,t)=0;%找到最小的顶点加入集合Sendre=r;1.2动态规划求解最短路径动态规划是美国数学家RichardBellman在1951年提出来的分析一类多阶段决策过程的最优化方法,在工程技术、工业生产、经济管理、军事及现代化控制工程等方面均有着广泛的应用。动态规划应用了最佳原理:假设为了解决某一优化问题,需要依次作出n个决策12,,,nDDD,如若这个决策是最优的,对于任何一个整数k,1kn,不论前面k个决策是怎样的,以后的最优决策只取决于由前面决策所确定的当前状态,即12,,,kknDDD也是最优的。如图1,从A1点要铺设一条管道到A16点,中间必须要经过5个中间站,第一站可以在{A2,A3}中任选一个,第二、三、四、五站可供选择的地点分别是:{A4,A5,A6,A7},{A8,A9,A10},{A11,A12,A13},{A14,A15}。连接两地管道的距离用连线上的数字表示,要求选一条从A1到A16的铺管线路,使总距离最短。1A2A1A3A4A5A6A7A8A9A10A13A12A11A14A15A1653136876683533842223335526643图1可选择的管道图解决此问题可以用穷举法,从A1到A16有48条路径,只须比较47次,就可得到最短路径为:A1→A2→A5→A8→A12→A15→A16,最短距离为18。也可以使用Dijkstra算法。这里,我们动态规划解决此问题。注意到最短路径有这样一个特性,即如果最短路径的第k站通过Pk,则这一最短路径在由Pk出发到达终点的那一部分路径,对于始点为Pk到终点的所有可能的路径来说,必定也是距离最短的。根据最短路径这一特性,启发我们计算时从最后一段开始,从后向前逐步递推的方法,求出各点到A16的最短路径。在算法中,我们用数组六元数组ss表示中间车站的个数(A1也作为中间车站),用距离矩阵path表示该图。为简便起见,把该图看作有向图,各边的方向均为从左到右,则path不是对称矩阵,如path(12,14)=5,而path(14,12)=0(用0表示不通道路)。用3´16矩阵spath表示算法结果,第一行表示结点序号,第二行表示该结点到终点的最短距离,第三行表示该结点到终点的最短路径上的下一结点序号。下面给出MATLAB实现算法。function[scheme]=ShortestPath(path,ss)%利用动态规划求最短路径%path是距离矩阵,ss是车站个数n=size(path,1);%结点个数scheme=zeros(3,n);%构造结果矩阵scheme(1,:)=1:n;%设置结点序号scheme(2,1:n-1)=realmax;%预设距离值k=n-1;%记录第一阶段结点最大序号fori=size(ss,2):-1:1;%控制循环阶段数forj=k:-1:(k-ss(i)+1);%当前阶段结点循环fort=find(path(j,:)0);%当前结点邻接结点ifpath(j,t)+scheme(2,t)scheme(2,j)scheme(2,j)=path(j,t)+scheme(2,t);scheme(3,j)=t;endendendk=k-ss(i);移入下一阶段end先在MATLAB命令窗口中构造距离矩阵path,再输入:ShortestPath(path,ss)得到以下结果:1234567891011121314151618131613109127687594302568891012121214151516160将该结果表示为图,即为图1粗线所示。棋盘覆盖问题1.1问题的提出在一个22kk个方格组成的棋盘中,若恰有一个方格与其他方格不同,则称该方格为一特殊方格,且称该棋盘为一特殊的棋盘。如图1就是当3k时的特殊棋盘。棋盘覆盖问题中,我们要用图2所示4种不同形态的L形骨牌覆盖一个特殊棋盘,且任何2个L型不得重叠覆盖。1.2问题的分析易知,用到的L型骨牌个数恰为(41)/3k。利用分治策略,我们可以设计出解棋盘覆盖问题的一个简捷的算法。图1当k=3时的特殊棋盘图24种不同形态的L型骨牌(a)(b)(c)(d)当k0时,我们将22kk棋盘分割为4个1122kk子棋盘如图3两粗实线所示。特殊方格必位于4个较小子棋盘之一中,其余3个子棋盘中无特殊方格。为了将这3个无特殊方格的子棋盘转化为特殊棋盘,我们可以用一个L型骨牌覆盖这3个较小棋盘的会合处,如图4中央L型骨牌所示,这3个子棋盘上被L型骨牌覆盖的方格就成为该棋盘上的特殊方格,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种分割,直至棋盘简化为11棋盘。1.3算法的MATLAB实现首先特殊方格在棋盘中的位置可以用一个12的数组sp表示;对于图2所示的4种L型骨牌,可用数字1,2,3,4表示;对于特殊棋盘的骨牌覆盖表示,只图3棋盘分割图4关键结点123须注意到图4所示的关键点,对每个关键点,给定一种L型骨牌,就能覆盖整个棋盘,所以对于22kk的特殊棋盘的骨牌覆盖,可用一个(21)(21)kk的矩阵表示。按照这种思想,图4的矩阵表示为:k=4,特殊方格位置为:[1,4],覆盖矩阵为:1040102040002040302030003000104030204000304030403下面是在MATLAB中的棋盘覆盖实现程序。functionre=chesscover(k,sp)%解决棋盘的覆盖问题%棋盘为2^k*2^k,sp为特殊方格的棋盘位置globalcovermatrixcovermatrix=zeros(2^k-1,2^k-1);even1=floor(sp(1,1)/2)*2==sp(1,1);%判断水平位置是否是偶数even2=floor(sp(1,2)/2)*2==sp(1,2);%判断竖直位置是否是偶数ifeven1==1&&even2==0%找出找出特殊方格相对关键结点的位置i=4;elsei=even1+even2+1;endtempfun(1,1,k,[sp(1,1)-even1,sp(1,2)-even2,i]);re=covermatrix;functiontempfun(top,left,k,tp)%子函数,tp为转换后特殊方格在棋盘网络的相对位置globalcovermatrixifk==1switchtp(1,3)case1covermatrix(tp(1,1),tp(1,2))=3;case2covermatrix(tp(1,1),tp(1,2))=4;case3covermatrix(tp(1,1),tp(1,2))=1;case4covermatrix(tp(1,1),tp(1,2))=2;endelsehalf=2^(k-1);i=top+half-1;j=left+half-1;iftp(1,1)iiftp(1,2)j%特殊方格在左上covermatrix(i,j)=3;%添加类型为3的L型骨牌tempfun(top,left,k-1,tp);tempfun(top,left+half,k-1,[i-1,j+1,4]);tempfun(top+half,left+half,k-1,[i+1,j+1,1]);tempfun(top+half,left,k-1,[i+1,j-1,2]);else%特殊方格在右上covermatrix(i,j)=4;%添加类型为4的L型骨牌tempfun(top,left,k-1,[i-1,j-1,3]);tempfun(top,left+half,k-1,tp);tempfun(top+half,left+half,k-1,[i+1,j+1,1]);tempfun(top+half,left,k-1,[i+1,j-1,2]);endelseiftp(1,2)j%特殊方格在右下covermatrix(i,j)=1;%添加类型为3的L型骨牌tempfun(top,left,k-1,[i-1,j-1,3]);tempfun(top,left+half,k-1,[i-1,j+1,4]);tempfun(top+half,left+half,k-1,tp);tempfun(top+half,left,k-1,[i+1,j-1,2]);else%特殊方格在左下covermatrix(i,j)=2;%添加类型为4的L型骨牌tempfun(top,left,k-1,[i-1,j-1,3]);tempfun(top,left+half,k-1,[i-1,j+1,4]);tempfun(top+half,left+half,k-1,[i+1,j+1,1]);tempfun(top+half,left,k-1,tp);endendend在MATLAB命令窗口中输入指令chesscover(3,[1,4])将会得到如上面矩阵一样的结果。结合VC++,利用MATLAB引擎库函数,可以给出了棋盘覆盖的图形最优树的应用实例1.1问题的提出已知某通信系统在通信联络中只可能出现8种字符,其概率分别为0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试设计一种编码,使得信息包长度达到最小。1.2问题的分析ASCII码是用8位(一个字节)表示一个字符,这种表示方法方便,易于理解,是计算机系统中常用的字符表示方法。在信息传输领域,可能有些字符出现的频率非常高,而有些字符出现的频率很低,若依然用此方法表示数据,则显得过于庞大,如果用不定长编码表示字符,频率出现高的字符用较短的编码表示,频率出现低的字符用较长的编码表示,则可以使得数据量大大减少。比如AAAABBBAAABBBBCCCCCCBBB,用ASCII码表示占用184位,若用00表示C,01表示A,1表