NOIP图的基础算法.ppt
《NOIP图的基础算法.ppt》由会员分享,可在线阅读,更多相关《NOIP图的基础算法.ppt(76页珍藏版)》请在三一办公上搜索。
1、NOIP 图的常用算法简介,石门中学江涛 2,目 录,图的表示邻接矩阵、邻接链表、图的遍历最小生成树算法 Prim算法、Kruskal算法最短路径算法Dijkstra算法、Bellman_Ford算法及SPFA算法、Floyd算法,目 录,图的表示邻接矩阵、邻接链表、图的遍历最小生成树算法 Prim算法、Kruskal算法最短路径算法Dijkstra算法、Bellman_Ford算法及SPFA算法、Floyd算法,顶点给点编号为连续的整数把顶点存放在数组中边邻接矩阵布尔值(或边权值)-TRUE 有边FALSE 无边空间复杂度O(|V|2),图的表示-邻接矩阵,边邻接链表每一个顶点有一个所有与之
2、相邻的链表每一条边2 个(对无向图)要在两个顶点的链表中都加入空间复杂度O(|E|)对稀疏图这种方式比较好,图的表示-邻接链表,图的邻接链表的Pascal和C+实现 具体参见NOIP基础数据结构ppt,图的表示-C/P语言程序实现,图的深度优先(Depth-First)遍历:邻接链表、C+,图的表示-图的遍历,/图的一般结构 struct graph_node;struct AdjList int id;AdjList*next;int n_nodes,S_index=0;graph_node nodes maxN;int visited maxN;AdjList*adj maxN;,标识项点
3、有没有访问过,每个顶点都有邻接链表,邻接链表的节点数据结构,图的深度优先(Depth-First)遍历:邻接链表、C+,图的表示-图的遍历,置每个点标识为“未访问”,从所有未被访问的点k出发,调用DFS(k),void search()int k;for(k=0;kn_nodes;k+)visitedk=0;for(k=0;kn_nodes;k+)if(!visitedk)DFS(k);,置被访问节点的“时间”-次序,访问k的所有相邻的节点,void DFS(int k)/从k出发搜索 AdjList*j;visitedk=+S_index;for(j=adjk;j!=NULL;j=j-nex
4、t)if(!visitedj-id)DFS(j-id);,图的深度优先(Depth-First)遍历:邻接链表、Pascal,图的表示-图的遍历,/图的一般结构 type graph_node=record end;type AdjList=record id:integer;next:AdjList;end;var n_nodes,S_i:integer;nodes:array1.maxN of graph_node;visited:array1.maxNof integer;adj:array1.maxN of AdjList;,标识项点有没有访问过,每个顶点都有邻接链表,邻接链表的节点数
5、据结构,图的深度优先(Depth-First)遍历:邻接链表、Pascal,图的表示-图的遍历,置每个点标识为“未访问”,从所有未被访问的点k出发,调用DFS(k),procedure search();begin k:integer;for k:=1 to n_nodes do visitedk:=0;for k:=1 to n_nodes do if visitedk0 then DFS(k);end;,置被访问节点的“时间”-次序,访问k的所有相邻的节点,procedure DFS(k:integer);begin/从k出发搜索 var j:AdjList;begin inc(S_i);
6、visitedk:=S_i;j:=adjk;while(jNULL)do begin if visitedj.id0 then DFS(j.id);j:=j.next;end;end;,图的宽度优先(Breadth-First)遍历:邻接链表、C+,图的表示-图的遍历,/图的一般结构 struct graph_node;struct AdjList int id;AdjList*next;int n_nodes,S_index=0;graph_node nodes maxN;int visited maxN;AdjList*adj maxN;,标识项点有没有访问过,每个顶点都有邻接链表,邻接链
7、表的节点数据结构,图的宽度优先(Breadth-First)遍历:邻接链表、C+,图的表示-图的遍历,置每个点标识为“未访问”,从所有未被访问的点k出发,调用BFS(k),void search()int k;for(k=0;kn_nodes;k+)visitedk=0;for(k=0;kn_nodes;k+)if(!visitedk)BFS(k);,图的宽度优先(Breadth-First)遍历:邻接链表、C+,图的表示-图的遍历,int q maxN;void BFS(int k)int front,back;q0=k;front=back=0;for(;fronnext)if(!visi
8、tedj-id)q+back=j-id;visitedj-id=+S_index;,BFS用的队列,一般全局,Front=back,队列不空,访问k的所有相邻的节点,图的宽度优先(Breadth-First)遍历实例示意:,图的表示-图的遍历,目 录,图的表示邻接矩阵、邻接链表、图的遍历最小生成树算法 Prim算法、Kruskal算法最短路径算法Dijkstra算法、Bellman_Ford算法及SPFA算法、Floyd算法,图的遍历:邻接链表时间复杂度分析每一个顶点访问一次每条边访问两次无向图每条边出现在两个链表中O(|V|+|E|)O(|V|2)对 稠密图|E|V|2 O(|V|)对 稀疏
9、图|E|V|对稀疏图邻接链表的效果非常好!,图的表示-图的遍历,生成树:一个|V|个点的图,取其中|V|-1条边,并连接所有的顶点,则组成原图的一个生成树。属性:|v|-1条边、连通、无环。最小生成树:加权图的最小生成树是一棵生成树,其所有边的权值之和不会大于其它任何生成树。简单讲:找出连接所有点的最低成本路线,最小生成树(MST)-定义,红边连接了所有顶点,所以构成一棵生成树权和=1+2+4+4+7+8+9,局域网(net)RQNOJ 某局域网内有n(n=100)台计算机,由于建网时工作人员的疏忽,现在网内存在回路,造成网络卡的现象。我们用f(i,j)表示i,j之间连接的畅通程度(f(i,j
10、)=1000),f(i,j)值越小表示i,j之间连接越通畅,f(i,j)为0表示i,j之间无网线连接。现在我们需要除去一些连线,使得网络中没有回路,并且被除去网线的f(i,j)最大,请求出这个最大值。,最小生成树(MST)-实例一,环属性:一棵生成树上,增加一条边e,再删除e所在环上的最大边,会得到另一棵“更好”的生成树(如果e不是最大边),最小生成树(MST)-算法原理,9,4,剪切属性:在图中,剪切将顶点划分成两个不相交集合。交叉边为地些顶点在两个不同集合的边。对于任何一个剪切,各条最小的交叉边都属于某个MST,且每个MST中都包含一条最小交叉边。,最小生成树(MST)-算法原理,7,4,
11、9,最小边原则:图中权值最小的边(如果唯一的话)一定在最小生成树上。唯一性:一棵生成树上,如果各边的权都不相同,则最小生成树是唯一的。反之不然。思考:怎样图G判断只有一个MST?,最小生成树(MST)-算法原理,算法描述1:MST_Prim(G,r)(1)将G剪切成两个集合A、B,A中只有一个点r(2)取最小权的交叉边(x,y),xB,yB(3)将y加入A(4)如果已经加了n-1条边,结束。否则,转(3)算法证明:根据剪切属性 图(?),最小生成树(MST)-Prim算法,算法要点:每次求最小权交叉边时,如果都重新计算,则显然要枚举(x,y)-xA,yB。O(n2)时间复杂度。其实每次A中只是
12、增加一个新顶点v,最多有交叉边(v,y),修改量只有与v有边的顶点,为O(n)。只需记录下B中的每个元素y与A所有元素中最小权边,则求最小值最多为O(n)-有时可以用“堆”优化。,最小生成树(MST)-Prim算法,算法描述2:MST_Prim(G,r)/从任意点r出发,生长成一MST for i=1 to n do disi/初始化每点到A集合的最小值 inAi false/设顶点不在A中disr 0/将r设为0(或-),准备取出for i=1 to n do v get-min()/取dis?中最小的值c和顶点v,inA v true/v放入A中 sum sum+c/c加入MST的总和中
13、updata(v)/枚举交叉边(v,B),改进dis,最小生成树(MST)-Prim算法,算法描述3:MST_Kruskal(G)(1)将G所有条边按权从小到大排序;图mst开始为空(2)从小到大次序取边(x,y)(3)若加入边(x,y),mst就有环,则放弃此边,转(2)(4)将边(x,y)加入mst,如果已经加了n-1条边,结束。否则,转(2)算法证明:根据剪切属性 图(?),最小生成树(MST)-Kruskal算法,算法要点:Kruskal算法的最难点在于怎样判断加入边(x,y)后是否形成了环。问题可化为:判断边(x,y)的两个顶点x,y在图(实际是森林)mst中最否已经连通。如果已经连
14、通,加入边将形成环;否则,不形成环。并查集:连通点集之类问题,有高效算法-并查集。,最小生成树(MST)-Kruskal算法,并查集:并查集详细内容可参见有关文章。下面是Pascal段:/初始化,使每个集合只一个元素。for i:=1 to n do f i:=i;/查找x所在类的“根”-代表,并压缩路径function find_set(x:longint):longint;begin if fxx then fx:=find_set(fx);exit(fx);end;/合并两个集合。x,y为两集合的“根”procedure union(x,y:longint);begin fx:=y;en
15、d;,最小生成树(MST)-Kruskal算法,并查集:并查集详细内容可参见有关文章。下面是C+片段:/初始化,使每个集合只一个元素。for(i=1;i=n;i+)f i=i;/查找x所在类的“根”-代表,并压缩路径int find_set(int x)if(fx!=x)fx=find_set(fx);return(fx);/合并两个集合。x,y为两集合的“根”void union(int x,y)fx=y;,最小生成树(MST)-Kruskal算法,算法描述4:MST_Kruskal(G)for i=1 to n do fi i;/初始化并查集 sort(e,e+m);/边按大小排序c 0;
16、/取边的计数器for i=1 to m do/从小到大取边 v find_set(ei.v);/左端点所在连通块“根”u find_set(ei.u);/右端点所在连通块“根”if(v!=u)/如果不在同一连通块 union(v,u);/合并两连通块 sum+=gvu;/加入这条边的权 if(+c=n-1)break;/if 取了n-1条边,结束,最小生成树(MST)-Kruskal算法,时间复杂度分析Prim算法普通的方法 O(|V|2)Prim算法中用“堆”方法 O(|E|+|V|)*log|V|)-对稀疏图较好Kruskal算法 O(|E|*log|E|+|N|*A(|V|)-对稀疏图较
17、好,最小生成树(MST)-时间复杂度,1、平面上有N(=3000)个点,求连通它们的最小生成树,用什么算法比较好?2、要判断一条边是否可以在一棵MST上,怎样做比较好?3、平面上有K个水源(井),N个居民供水点,怎样用最少的管道使这N个居民点都能用连接到水源。注:边只能水源、居民点之间直接相连。,最小生成树(MST)-思考题,maintain 有一个无向图,有N个点,有w条边。但是一开始,所有的边都是被破坏了的,即不可用。接下来每一天可以修复一条边。注意:两个点之间可能有多条边。现在的问题是:每一天修复完一条边后,无向图中的任意两个结点都可以连通了吗?如果还不可以输出-1,如果可以了,你从已经
18、修复的边中,选择一些边,使得这些边的总长度最小,输出最小值。,最小生成树(MST)-实例二,输入格式:第一行:两个整数:N,W。N(1=N=200)、W(1=W=6000).第2.W+1行:三个整数x,y,d.表示该天修复的边,该边是从结点x到结点y,长度是d.输出格式:每读入一条边,如果还不可以输出-1;如果可以了,你从已经修复的边中,选择一些边,使得这些边的总长度最小,输出最小值。,最小生成树(MST)-实例二,样例输入:4 61 2 101 3 83 2 31 4 31 3 62 1 2,最小生成树(MST)-实例二,样例输出:-1(4号点无法连接到其他点)-1(4号点无法连接到其他点)
19、-1(4号点无法连接到其他点)14(修2,3,4三边)12(修3,4,5三边)8(修3,4,6三边),2,1,4,3,10,8,3,3,分析:每读入一条边,做一次MST。最好:M*N*N=24,000,000 超1s动态维护树1、构成第一棵MST 2、读入边e(a,b,c),BFS找 e.a,e.b 所在路径,取其中边最大的x,如果 x.c e.c,删除边x,加入边e.M*N 1,200,000简化算法?由于每次只保留N-1条边,每次重新做Kruskal算法:M*N*logN 9,600,000 大致可行。更可省略排序,用插入法即可:M*N*3 3,600,000,最小生成树(MST)-实例二
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- NOIP 基础 算法
链接地址:https://www.31ppt.com/p-5441526.html