1. 圖與網(wǎng)絡(luò)的基本概念與數(shù)據(jù)結(jié)構(gòu)
- 一個(gè)圖是由一些點(diǎn)以及這些點(diǎn)之間得連線所組成的
- 兩點(diǎn)間不帶箭頭的連線為邊,帶箭頭的連線為弧
- 若邊
步势,則稱e連接u與v;點(diǎn)u妈嘹,v稱為e的頂點(diǎn)
- 如果兩條邊有一個(gè)公共頂點(diǎn)柳琢,則稱這兩條邊是鄰接的;兩個(gè)頂點(diǎn)重合為一點(diǎn)的邊稱為環(huán)
1.1 無向圖
如果一個(gè)圖是由點(diǎn)以及邊所構(gòu)成的润脸,則稱為無向圖柬脸,記為,一個(gè)圖稱為有限圖,如果它的頂點(diǎn)集和邊集都有限毙驯。圖G 的頂點(diǎn)數(shù)用符號(hào)
表示倒堕,邊數(shù)用
表示。
1.2 有向圖
如果一個(gè)圖是由點(diǎn)以及弧所構(gòu)成的爆价,則稱為有向圖垦巴,記為
1.3 完全圖,二分圖
- 設(shè)
是一個(gè)簡(jiǎn)單圖铭段,當(dāng)滿足
時(shí)
每一對(duì)不同的頂點(diǎn)都有一條邊相連的簡(jiǎn)單圖稱為完全圖(complete graph)骤宣。 - 設(shè)
是一個(gè)圖,若存在V的一個(gè)分劃
,是G的每條邊有一個(gè)頂點(diǎn)在
中,另一個(gè)在
中序愚,則稱G為二分圖涯雅。
1.4 子圖
1.5 頂點(diǎn)的度
頂點(diǎn)的度是指圖中與頂點(diǎn)相關(guān)聯(lián)的邊的數(shù)目
1.6 圖與網(wǎng)絡(luò)的數(shù)據(jù)結(jié)構(gòu)
1.6.1 鄰接矩陣表示法
定義:就是0-1矩陣,如果元素cij為“1”表示弧從第i個(gè)到第j個(gè)點(diǎn)展运,為“0”的話表示沒有活逆。如果是無向圖則必定cij=cji。
1.6.2 稀疏矩陣表示法
當(dāng)矩陣中0的個(gè)數(shù)比較少時(shí)拗胜,可以通過僅僅儲(chǔ)存非0元素的坐標(biāo)以及值來表示一個(gè)矩陣
像這樣:
(3,1) 35
(4,1) 21
(5,1) 51
(3,2) 21
(6,5) 13
構(gòu)造系數(shù)矩陣的兩種方法
- S=sparse(X)—將矩陣X轉(zhuǎn)化為稀疏矩陣的形式蔗候,即矩陣X中任何零元素去除,非零元素及其下標(biāo)(索引)組成矩陣S埂软。 如果X本身是稀疏的锈遥,sparse(X)返回S
a=[1,0,2;0,0,1;0,0,6];
>> a
3
a =
1 0 2
0 0 1
0 0 6
>> b=sparse(a)
b =
(1,1) 1
(1,3) 2
(2,3) 1
(3,3) 6
-
S = sparse(i,j,s,m,n,nzmax)——由i,j,s三個(gè)向量創(chuàng)建一個(gè)m*n的稀疏矩陣(上面的B矩陣形式),并且最多含有nzmax個(gè)元素勘畔。
例如:B=sparse([1,2,3],[1,2,3],[0,1,2],4,4,4)
B =
(2,2) 1(3,3) 2
其中i=[1,2,3]所灸,稀疏矩陣的行位置;j=[1,2,3]炫七,稀疏矩陣的列位置爬立;s=[0,1,2],稀疏矩陣元素值万哪。 其位置為一一對(duì)應(yīng)侠驯。
m=4(>=max(i)),n=4(>=max(j)) (注:m和n的值可以在滿足條件的范圍內(nèi)任意選取),用于限定稀疏的大小奕巍。
nzmax=4(>=max(i or j))吟策,稀疏矩陣最多可以有nzmax個(gè)元素。
2. 最短路問題
從圖中的某個(gè)頂點(diǎn)出發(fā)到達(dá)另外一個(gè)頂點(diǎn)的所經(jīng)過的邊的權(quán)重和最小的一條路徑的止,稱為最短路徑檩坚。
2.1 兩個(gè)指定頂點(diǎn)之間的最短路徑
解決問題的方法:
迪杰斯特拉算法(Dijkstra算法)-----經(jīng)典
弗洛伊德算法(Floyd算法)-----用三層循環(huán)
通過Floyd計(jì)算圖G=(V,E)中各個(gè)頂點(diǎn)的最短路徑時(shí),需要引入矩陣诅福,
矩陣S中的元素 map[i][j] 表示頂點(diǎn)i(第i個(gè)頂點(diǎn))到頂點(diǎn)j(第j個(gè)頂點(diǎn))的距離匾委。
假設(shè)圖G中頂點(diǎn)個(gè)數(shù)為N,則需要對(duì)矩陣D和矩陣P進(jìn)行N次更新权谁。
初始時(shí)剩檀,矩陣D中頂點(diǎn) map[i][j] 的距離為頂點(diǎn)i到頂點(diǎn)j的權(quán)值;
如果i和j不相鄰旺芽,則 map[i][j]=∞沪猴。 接下來開始,對(duì)矩陣D進(jìn)行N次更新采章。
第1次更新時(shí)运嗜,如果”a[i][j]的距離” > “a[i][k]+a[k][j]”
a[i][0]+a[0][j]表示”i與j之間經(jīng)過第1個(gè)頂點(diǎn)的距離”,則更新a[i][j]為”a[i][0]+a[0][j]”悯舟。 同理担租,第k次更新時(shí),如果”a[i][j]的距離” > “a[i][k-1]+a[k-1][j]”抵怎,則更新a[i][j]為”a[i][k-1]+a[k-1][j]”奋救。更新N次之后岭参,操作完成!
可以通過調(diào)用matlab圖論工具箱中的graphshortestpath函數(shù)直接進(jìn)行計(jì)算
3. 最小生成樹問題
一般可以使用matlab圖論工具箱中的graphminspantree()函數(shù)來求得最小生成樹尝艘。
【例】
clc
clear
%將數(shù)據(jù)寫成三元組的形式
x = [2,3,3,4,4,4,5,5,5,5,6,6,6,6,6];
y = [1,1,2,1,2,3,1,2,3,4,1,2,3,4,5];
w = [56,35,21,21,57,36,51,78,68,51,60,70,68,61,13];
a = sparse(x,y,w,6,6);%轉(zhuǎn)為稀疏矩陣
ug = tril(a+a');%轉(zhuǎn)化為下三角行列式
view(biograph(ug,[],'ShowArrows','off','ShowWeight','on'));
[st,pred]=graphminspantree(ug)%生成最小生成樹
nodestr = ['L','M','N','Pe','T'];
h=view(biograph(st,nodestr,'ShowArrows','off','ShowWeights','on'));
Edges=getedgesbynodeid(h);%提取無向圖h的邊集
set(Edges,'LineColor',[0 0 0]);%設(shè)置顏色屬性
set(Edges,'LineWidth',1.5)%設(shè)置邊值屬性
>>
st =
(3,1) 35
(4,1) 21
(5,1) 51
(3,2) 21
(6,5) 13
pred =
0 3 1 1 1 5
其中st是一個(gè)代表生成樹的稀疏矩陣演侯,pred是包含最小生成的祖先節(jié)點(diǎn)的向量
該圖的網(wǎng)絡(luò)如下:
該圖的最小生成樹如下:
4. 網(wǎng)絡(luò)最大流問題
假設(shè)現(xiàn)在有一個(gè)地下水管道網(wǎng)絡(luò),有m根管道背亥,n個(gè)管道交叉點(diǎn)秒际,現(xiàn)在自來水廠位于其中一個(gè)點(diǎn),向網(wǎng)絡(luò)中輸水狡汉,鄰居在另外一個(gè)點(diǎn)接水娄徊,已知由于管道修建的年代不同,有的管道能承受的水流量較大盾戴,有的較小寄锐,現(xiàn)在求在自來水廠輸入的水不限的情況下,鄰居能接到的水的最大值捻脖?
為解決該問題锐峭,可以將輸水網(wǎng)絡(luò)抽象成一個(gè)聯(lián)通的有向圖,每根管道是一條邊可婶,交叉點(diǎn)為一個(gè)結(jié)點(diǎn)沿癞,從u流向v的管道能承受的最大流量稱為容量,設(shè)為矛渴,而該管道實(shí)際流過的流量設(shè)為
椎扬,自來水廠稱為源點(diǎn)
,隔壁老王家稱為匯點(diǎn)
具温,則該問題求的是最終流入?yún)R點(diǎn)的總流量
的最大值蚕涤。
4.1 思路分析
關(guān)于最大流問題的解法大致分為兩類:增廣路算法和預(yù)流推進(jìn)算法。增廣路算法的特點(diǎn)是代碼量小铣猩,適用范圍廣揖铜,因此廣受歡迎;而預(yù)流推進(jìn)算法代碼量比較大达皿,經(jīng)常達(dá)到200+行天吓,但運(yùn)行效率略高
為了便于理解,先引入一個(gè)引理:最大流最小割定理峦椰。
在一個(gè)連通圖中龄寞,如果刪掉若干條邊,使圖不聯(lián)通汤功,則稱這些邊為此圖的一個(gè)割集物邑。在這些割集中流量和最小的一個(gè)稱為最小割。
最大流最小割定理:一個(gè)圖的最大流等于最小割。
大開腦洞一下色解,發(fā)現(xiàn)此結(jié)論顯而易見茂嗓,故略去證明(其實(shí)嚴(yán)格的證明反而不太好寫,但是很容易看出結(jié)論是對(duì)的科阎,是吧)在抛。這便是增廣路算法的理論基礎(chǔ)。
在圖上從s到t引一條路徑萧恕,給路徑輸入流flow,如果此flow使得該路徑上某條邊容量飽和肠阱,則稱此路徑為一條增廣路票唆。增廣路算法的基本思路是在圖中不斷找增廣路并累加在flow中,直到找不到增廣路為止屹徘,此時(shí)的flow即是最大流走趋。可以看出噪伊,此算法其實(shí)就是在構(gòu)造最小割簿煌。
可以通過matlab中的graphmaxflow求解,調(diào)用格式如下:
[MaxFlow, FlowMatrix, Cut] = graphmaxflow(G, SNode, TNode)
[...] = graphmaxflow(G, SNode, TNode, ...'Capacity', CapacityValue, ...)
[...] = graphmaxflow(G, SNode, TNode, ...'Method', MethodValue, ...)
【注意】有的時(shí)候K為二維矩陣,即存在不唯一的割集鉴吹。
給出例子如下:
clc
clear
a = zeros(6);
x = [1,1,2,2,3,3,4,5,5];
y = [2,4,3,4,4,6,5,3,6];
w = [8,7,9,5,2,5,9,6,10];
z = sparse(x,y,w,6,6);
h = view(biograph(z,[],'ShowWeights','on'));
[M,F,K] = graphmaxflow(z,1,6)
view(biograph(F,[],'ShowWeights','on'))
set(h.Nodes(K(1,:)),'Color',[1 0 0])
>>
M =
14
F =
(1,2) 8
(2,3) 5
(1,4) 6
(2,4) 3
(4,5) 9
(3,6) 5
(5,6) 9
K =
1×6 logical 數(shù)組
1 1 1 1 0 0
5. 最小費(fèi)用最大流問題
最小費(fèi)用最大流是解決這么一種問題: 對(duì)于圖中的每一條邊來說, 除了有一個(gè)最大容量的屬性以外姨伟,還有一個(gè)費(fèi)用屬性, 即流過這條邊的單位流量的花費(fèi)。求解的問題為在保證從源點(diǎn)到匯點(diǎn)的流量最大的前提下使得花費(fèi)最少豆励。
【例】
下面自己編寫mincostmaxflow函數(shù)(matlab中無工具箱可以調(diào)用):
%最小費(fèi)用最大流函數(shù)
function[flow,val]=mincostmaxflow(rongliang,cost,flowvalue);
%第一個(gè)參數(shù):容量矩陣夺荒;第二個(gè)參數(shù):費(fèi)用矩陣;
%前兩個(gè)參數(shù)必須在不通路處置零
%第三個(gè)參數(shù):指定容量值(可以不寫良蒸,表示求最小費(fèi)用最大流)
%返回值 flow 為可行流矩陣,val 為最小費(fèi)用值
global M
flow=zeros(size(rongliang));allflow=sum(flow(1,:));
if nargin<3
flowvalue=M;
end
while allflow<flowvalue
w=(flow<rongliang).*cost-((flow>0).*cost)';
path=floydpath(w);%調(diào)用 floydpath 函數(shù)
if isempty(path)
val=sum(sum(flow.*cost));
return;
end
theta=min(min(path.*(rongliang-flow)+(path.*(rongliang-flow)==0).*M));
theta=min([min(path'.*flow+(path'.*flow==0).*M),theta]);
flow=flow+(rongliang>0).*(path-path').*theta;
allflow=sum(flow(1,:));
end
val=sum(sum(flow.*cost));
其中用到floydpath函數(shù)求最短路徑:
%求最短路徑函數(shù)
function path=floydpath(w);
global M num
w=w+((w==0)-eye(num))*M;
p=zeros(num);
for k=1:num
for i=1:num
for j=1:num
if w(i,j)>w(i,k)+w(k,j)
w(i,j)=w(i,k)+w(k,j);
p(i,j)=k;
end
end
end
end
if w(1,num) ==M
path=[];
else
path=zeros(num);
s=1;t=num;m=p(s,t);
while ~isempty(m)
if m(1)
s=[s,m(1)];t=[t,t(1)];t(1)=m(1);
m(1)=[];m=[p(s(1),t(1)),m,p(s(end),t(end))];
else
path(s(1),t(1))=1;s(1)=[];m(1)=[];t(1)=[];
end
end
end
最后編寫求解函數(shù):
function mainexample19
clear;clc;
global M num
c=zeros(6);u=zeros(6);
c(1,2)=2;c(1,4)=8;c(2,3)=2;c(2,4)=5;
c(3,4)=1;c(3,6)=6;c(4,5)=3;c(5,3)=4;c(5,6)=7;
u(1,2)=8;u(1,4)=7;u(2,3)=9;u(2,4)=5;
u(3,4)=2;u(3,6)=5;u(4,5)=9;u(5,3)=6;u(5,6)=10;
num=size(u,1);M=sum(sum(u))*num^2;
[f,val]=mincostmaxflow(u,c)
>>
f =
0 8 0 6 0 0
0 0 7 1 0 0
0 0 0 2 0 5
0 0 0 0 9 0
0 0 0 0 0 9
0 0 0 0 0 0
val =
205
6. matlab 圖論工具箱
命令名 | 功能 |
---|---|
graphallshortestpaths | 求圖中所有頂點(diǎn)對(duì)之間的最短距離 |
graphconncomp | 找無向圖的連通分支技扼,或有向圖的強(qiáng)弱連通分支 |
graphisdag | 測(cè)試有向圖是否含有圈,不含圈返回1嫩痰,否則返回0 |
graphisomorphism | 確定兩個(gè)圖是否同構(gòu)剿吻,同構(gòu)返回1,否則返回0 |
graphisspantree | 確定一個(gè)圖是否是生成樹串纺,是返回1丽旅,否則返回0 |
graphmaxflow | 計(jì)算有向圖的最大流 |
graphminspantree | 在圖中找最小生成樹 |
graphpred2path | 把前驅(qū)頂點(diǎn)序列變成路徑的頂點(diǎn)序列 |
graphshortestpath | 求圖中指定的一對(duì)頂點(diǎn)間的最短距離和最短路徑 |
graphtopootder | 執(zhí)行有向無圈圖的拓?fù)渑判?/td> |
graphtraverse | 求從一頂點(diǎn)出發(fā),所能遍歷圖中的頂點(diǎn) |
給出例子如下:
【例】用matlab求解從Node1到Node11的最短路徑及長(zhǎng)度
clc, clear
a(1,2)=2;a(1,3)=8;a(1,4)=1;
a(2,3)=1;a(2,3)=6;a(2,5)=1;
a(3,4)=7;a(3,5)=5;a(3,6)=1;a(3,7)=2;
a(4,7)=9;
a(5,6)=3;a(5,8)=2;a(5,9)=9;
a(6,7)=4;a(6,9)=6;
a(7,9)=3;a(7,10)=1;
a(8,9)=7;a(8,11)=9;
a(9,10)=1;a(9,11)=2;
a(10,11)=4;
a=a'; %matlab工具箱要求數(shù)據(jù)是下三角矩陣
[i,j,v]=find(a);
b=sparse(i,j,v,11,11) %構(gòu)造稀疏矩陣
[x,y,z]=graphshortestpath(b,1,11,'Directed',false) % Directed是標(biāo)志圖為有向或無向的屬性造垛,該圖是無向圖魔招,對(duì)應(yīng)的屬性值為false,或0五辽。
h = view(biograph(b,[],'ShowArrows','off','ShowWeights','on'))
set(h.Nodes(y),'Color',[1 0.4 0.4])
fowEdges = getedgesbynodeid(h,get(h.Nodes(y),'ID'));
revEdges = getedgesbynodeid(h,get(h.Nodes(fliplr(y)),'ID'));
edges = [fowEdges;revEdges];
set(edges,'LineColor',[1 0 0])
set(edges,'LineWidth',1.5)
>>
x =
13
y =
1 2 5 6 3 7 10 9 11
z =
0 1 6 1 2 5 3 5 10 7 9
得到最短路線如下:
【說明】
- find函數(shù)可以返回元素的橫縱坐標(biāo)办斑,以及值
- 記得變成下三角行列式
- sparse函數(shù)創(chuàng)造系數(shù)矩陣,只記錄矩陣中非零元素的左邊以及值
- graphshortestpath的第一個(gè)參數(shù)代表最短路程,第二個(gè)參數(shù)為途中的標(biāo)號(hào)即最短路徑是13乡翅,最短路徑為1-2-5-6-3-7-10-9-11