⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 judge1.txt

📁 判断连通图
💻 TXT
字号:
1连通图--对无向图,任意Vi<>Vj的两个顶点之间都存在路径   
  2强连通图--对有向图,任意Vi<>Vj的两个顶点之间都存在Vi→Vj,Vj→Vi的路径   
  3连通分量--无向图的极大连通子图   
  4强连通分量--有向图的极大连通子图   
    判断一个无向图是否为连通图或连通分量很容易,而判断一个   有向图是否为强连通图或强连通分量则比较困难,可采用下列方法,若一个有向图是强连通图或强连通分量,则一定能找到包含所有顶点在内的若干独立的有向回路。     
  5网路--边或弧带有权值的图,又称为带权图。   
  6生成树--图的无环连通子图   
    在一个图中究竟会有多少边或弧呢?我们先看看无向图:最少当然可能只有0条边,最多时即当任何两个顶点之间都有相联系的边时,边数将达到n*(n-1)/2。具有n*(n-1)/2条边的无向图我们称之为完全图。对于有向图,e的取值范围是0到n(n-1),我们也把有n*(n-1)条弧的有向图称为有向完全图。对那些边或弧很少的图称之为稀疏图,反之称稠密图。有的时候,图的边或弧上还带有一个相关的数(称为权),表示从一个顶点到另一个顶点的耗费,这种图就叫做网。     
    一般采用一些改进的方式来存储图,常用的有邻接表和十字链表等。下面我们以邻接表为例来说明一下:   
    邻接表(adjacency   list)是图的一种链式存储结构。在邻接表中,对图中每个顶点建立一个单链表,第i个单链表中的结点表示依附于顶点vi的边(或以vi为尾的弧)。很自然的,每个结点将由三个域组成,其中邻接点域(adjvex)指示与顶点vi邻接的点在图上的位置,链域(nextarc)指示下一条边或弧   的结点;数据域(info)存储和边或弧相关的信息,如权值等。     
    每个链表上附设一个表头结点。在每个表头结点中,除了设有链域之外,还有存储顶点vi的名或其它有关信息的数据域(vexdata)。这些表头结点通常以顺序结构的形式存储,以便能够随机访问任一顶点的链表。     
    下面的图将告诉你邻接表是如何构造出来的。   
    十字链表(ortholgonal   list)是有向图的另一种链式存储结构。可以看成是将有向图的邻接表和逆邻接表结合起来得到的一种链表。在十字链表中,对应于有向图中每一条弧有一个结点,对应于每个顶点也有一个结点。这些结点根据顶点和弧的联系关系交织成网状   
          最后要注意两点:一个图的邻接矩阵表示是唯一的,而一个图的邻接表表示是不唯一的。   
    图的遍历算法:   
    因为图是一种非线性数据结构,因此我们有使其序列化的需要--即图的遍历。和树的遍历类似,图的遍历(traversing   graph),就是从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次。图的遍历算法是其后我们要学习的许多算法的基础。     
    按照搜索次序的不同,通常有两种遍历图的方法:深度优先搜索和广度优先搜索。它们对无向图和有向图都适用。   
    深度优先搜索(depth一first   search)遍历类似于树的先根遍历。     
    假设初始状态是图中所有顶点未曾被访问,则深度优先搜索可从图中某个顶点v0出发,访问此顶点,然后依次从vo的未被访问的邻接点出发深度优先遍历图,直至图中所有和v0有路径相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。     
    显然,这是一个递归的过程。为了在遍历过程中便于区分顶点是否已被访问,需附设访问标志数组visited[   1:n],其初值为"false",一旦某个顶点被访问,则其相应的分量置为   "true"。整个图的遍历算法如下所示。你也可以通过演示加深印象。   
    void   traver_dfs(Graph   g,bool   visited[])   
    {   /*对图按深度优先进行遍历*/   
    for   (i=1;i<=vexnum;i++)   
    visited[i]=false;//标志数组初始化   
    for   (i=1;i<=vexnum;i++)   
    if   (!visited[i])   
    dfs(g,i);   
    }   
    void   dfs(Graph   g   ,vtx   *   v0){   
    /*从v0出发深度优先遍历图g*/   
    visit(v0);   
    visited[v0]   =   true;   
    w=FIRSTADJ(g,v0);   //w为v0的邻接点   
    while   (w!=0)   {   //当邻接点存在时   
    if   (!visited[w])   
    dfs   (g,w);   
    w=   NEXTADJ(g,v0,w)//找下一邻接点   
    }   
    }//dfs   
    分析上述过程,在遍历图时,对图中每个顶点至多调用一次dfs过程,因为一旦某个顶点被标志成已被访问,就不再从它出发进行搜索。因此,遍历图的过程实质上是对每个顶点查找其邻接点的过程。其耗费的时间则取决于所采用的存储结构。当用二维数组表示邻接矩阵作图的存储结构时,查找每个顶点的邻接点所需时间为O(n2),其中n为图中顶点数。而当以邻接表作图的存储结构时,找邻接点所需时间为O(e),其中e为无向图中边的数或有向图中弧的数。由此,当以邻接表作存储结构时,深度优先搜索遍历图的时间复杂度为O(n+e)。     
    广度优先搜索(breadth一first   search)遍历类似于树的按层次遍历的过程。   假设从图中某顶点v0出发,在访问了v0之后依次访问v0的各个未曾访问过的邻接点,然后分别从这些邻接点出发广度优先搜索遍历图,直至图中所有已被访问的顶点的邻接点都被访问到。若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。换句话说,广度优先搜索遍历图的过程是以v0为起始点,由近至远,依次访问和v0有路径相通且路径长度为1,2,…的顶点。     
    和深度优先搜索类似,在遍历的过程中也需要一个访问标志数组。并且,为了顺次访问路径长度为2、3、…的顶点,需附设队列以存储已被访问的路径长度为1,2,…的顶点。广度优先遍历的算法如下所示。     
    分析上述过程,每个顶点至多进一次队列。遍历图的过程实质上是通过边或弧找邻接点的过程、因此广度优先搜索遍历图的时间复杂度和深度优先搜索遍历相同,两者不同之处仅仅在于对顶点访问的顺序不同。     
    void   traver_bfs(Graph   g,bool   visited[]){   /*对图按广度优先进行遍历*/   
    for   (i=1;i<=vexnum;i++)   
    visited[i]=false;//标志数组初始化   
    for   (i=1;i<=vexnum;i++)   
    if   (!visited[i])   
    dfs(g,i);   
    }   
    void   bfs(Graph   g   ,vtx   *   v0){   
    /*从v0出发广度优先遍历图g*/   
    visit(v0);   
    visited[v0]=true;   
    INIQUEUE(Q);//初始化队列   
    ENQUEUE(Q,v0);   
    while   (!EMPTY(Q))   {   
    v=DLQUEUE(Q);   //队头元素出队   
    w=FIRSTADJ(g,v);//求v的邻接点   
    while   (w!=0){   
    if   (!visited[w])   {   
    visit(w);   
    visited[w]=true;   
    ENQUEUE(Q,w);   
    }   
    w=NEXTADJ(g,v,w);//求下一邻接点   
    }   
    }   
    }//bfs   

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -