zoukankan      html  css  js  c++  java
  • 图总结

    图的知识点总结

    一、思维导图

    二、重要概念笔记

    1. 图的定义和基本术语

      1. 定义

        • 图:是由一个顶点集 V 和一个顶点间的关系集合 组成的数据结构。

        • “弧”是有方向的,因此称由顶点集和弧集构成的 图为有向图

        • 由顶点集和边集构成的图称作无向图

      2. 基本术语

        • 有(无)向网:弧或边带权的图

        • 完全图:含有e=n(n-1)/2条边的无向图

        • 有向完全图:含有e=n(n-1)条弧的有向图称作有向完全图

        • 稀疏图:e<nlogn;稠密图:e>=nlogn

        • 度=出度(以顶点v为弧尾的弧的数目)+入度(以顶点v为弧头的弧的数目)仅对有向图

        • 路径长度:从顶点v到顶点w路径上边的数目;简单路径:序列中顶点不重复出现的路径;简单回路:序列中第一个顶点和最后 一个顶点相同的路径

        • 对无向图:若图G中任意两个顶点之间都有路径相通,则称此图为连通图:若无向图为非连通图,则图中各个极大连通子图,称作此图的连通分量。对有向图:若任意两个顶点之间都存在一条有向路径,则称此 有向图为强连通图。否则,其各个强连通子图称作它的强连通分量

    2. 图的存储结构

      1. 邻接矩阵: 无向图的邻接矩阵是对称的,有向图的邻接矩阵可能是不对称的。在有向图中:①出度:统计第i行1的个数②入度:统计第j列1的个数。

        含有n个顶点和e条边的无向图的邻接矩阵中,零元素的个数为:n^2-2e

        #define MaxInt 32767 //表示极大值 
        #define MVNum 100    //最大顶点数 
        typedef char VerTexType; 
        //假设定点的数据类型为字符型 
        typedef int ArcType; //假设边的权值类型为整型 typedef struct {     // 图的定义 
        	VerTexType vexs[MVNum];     // 顶点表
            ArcType arcs[MVNum][MVNum]; 
            // 弧的信息(邻接矩阵) 
            int    vexnum, arcnum;      
            // 图当前的顶点数和边数 
         } AMGraph;  //邻接矩阵
        
        

      2. 邻接表:邻接点域、链域、数据域。

        //表(弧/边)结点: 
        typedef struct ArcNode {  
        	int   adjvex; // 该弧所指向的顶点的位置 
        	struct ArcNode *nextarc;//指向下一条弧的指针
        	InfoType *info;  // 该弧相关信息的指针 
        } ArcNode;
        //头结点: 
        typedef struct VNode { 
        	VerTexType data;   // 顶点信息 
        	ArcNode *firstarc; // 指向第一条依附该顶点的弧 
        } VNode, AdjList[MAX_VERTEX_NUM];
        
        

        无向图邻接表:

        有向图邻接表:

      3. 十字链表:从横向上看是邻接表,从纵向看是逆邻接表

        typedef struct ArcBox { // 弧的结构表示 
        	int tailvex, headvex;   
        	InfoType *info; 
        	struct ArcBox *hlink, *tlink;   
        } VexNode;
        typedef struct VexNode { // 顶点的结构表示 
        	VertexType  data; 
        	ArcBox  *firstin, *firstout;   
        } VexNode;
        
        

    3. 图的遍历

      1. 深度优先遍历(DFS)

        int visit[2*MAX];
        void dfs(Graph G,int s){
              Arc* p = G.vex[s].firstArc;
              if(!visit[s]){
                  printf("%4s",G.vex[s].data);
                  visit[s] = 1;
              }
              while(p != NULL){
                  if(!visit[p->adjvex])
                      dfs(G,p->adjvex);
                  p = p->nextArc;
              }
         }
        
      2. 广度优先算法(BFS)

        int q[2*MAX],f=0,r=0;
        int visit_q[MAX];
          void bfs(Graph G,int s){
              if(!visit_q[s]){
                  printf("%4s",G.vex[s].data);
                  visit_q[s] = 1;
                  Arc* p = G.vex[s].firstArc;
                  while(p != NULL){
                     if(!visit_q[p->adjvex])
                         q[r++] = p->adjvex;
                     p = p->nextArc;
                 }
             }
             while(f < r){
                 bfs(G,q[f++]);
             }
         }
        
    4. 最小生成树

      构造的最小生成树并不一定唯一,但最小生成树的权值之和一定是相同的。

      1. 普利姆算法:

        #define INF 32767
        void Prim(MGraph g,int v){
        	int lowcost[MAXv];
        	int min;
        	int closest[MAXV],i,j,k;
        	for(i=0;i<g.n;i++){
        		lowcost[j]=g.edges[v][i];
        		closest[i]=v;
        	}
        	for(i=1;i<g.n;i++){
        		min=INF;
        		for(j=0;j<g.n;j++){
        			if(lowcost[j]!=0&&lowcost[j]<min){
        				min=lowcost[j];
        				k=j;
        			}
        			printf("边(%d,%d)权为:%d
        ",closest[k],k,min);
        			lowcost[k]=0;
        		}
        		for(j=0;j<g.n;j++){
        		if(g.edges[k][j]!=0&&g.edges[k][j]<lowcost[j]){
        				lowcost[j]=g.edges[k][j];
        				closest[j]=k;
        			}
        		}
        	}
        }
        
      2. 克鲁斯卡尔算法:

        void Kruskal(MGraph g){
        	int i,j,u1,v1,sn1,sn2,k;
        	int vset[MAXV];
        	Edge E[MaxSize];
        	k=0;
        	for(i=0;i<g.n;i++){
        		for(j=0;j<g.n;j++){
        			if(g.edges[i][j]!=0&&g.edges[i][j]!=INF){
        				E[k].u=i;E[k].v=j;
        				E[k].w=g.edges[i][j];
        				k++;
        			}
        		}
        	}
        	InsertSort(E,g,e);
        	for(i=0;i<g.n;i++) vest[i]=i;
        	k=1;j=0;
        	while(k<g.n){
        		u1=E[j].u;v1=E[j].v;
        		sn1=vset[u1];sn2=vset[v1];
        		if(sn1!=sn2){
        			cout<<u1,v1,E[j].w;
        			k++;
        			for(i=0;i<g.n;i++)
        				if(vset[i]==sn2) 
        					vset[i]=sn1;
        		}
        		j++;
        	}
        }
        
    5. 最短路径(与关键路径区分!)

      1. Dijkstra算法:把V分成两组: ⑴S:已求出最短路径的顶点的集合 ⑵T=V-S:尚未确定最短路径的顶点集合 将T中顶点按最短路径递增的次序加入到S中,保证:① 从源点V0到S中各顶点的最短路径长度都不大于从V0到T 中任何顶点的最短路径长度 ②每个顶点对应一个距离值: ③S中顶点:从V0到此顶点的最短路径长度 ④T中顶点:从V0到此顶点的只包括S中顶点作中间顶点的最 短路径长度

      2. Floyd算法:逐个顶点试探 从vi到vj的所有可能存在的路径中,选出一条长度最 短的路径。

    6. 拓扑排序

      按照有向图给出的次序关系,将图中顶点排成一个 线性序列,对于有向图中没有限定次序关系的顶点, 则可以人为加上任意的次序关系。 由此所得顶点的线性序列称之为拓扑有序序列(有向无环图)

      进行拓扑排序:①从有向图中选取一个没有前驱的顶点,并输出之; ②从有向图中删去此顶点以及所有以它 为尾 的弧; ③重复上述两步,直至图空,或者图不空但找不到无 前驱的顶点为止。

    7. 关键路径

      概念:

      事件vi的最早发生时间:从开始点v1到vi的最长路 径长度。用ve(i)表示。

      事件vi的最迟发生时间:在不推迟整个工期的前提 下,事件vi允许的最晚发生时间。用vl(i)表示。

      关键路径(最长路径):

    三、疑难问题及解决方案

    1.pta 7-6 旅游规划

    #include <stdio.h>
    #include <stdlib.h>
    #define T 500
    #define INF 999999
    int main(){
        int G[T][T];//存储最短距离 
        int p[T][T];//储存收费额
        int N,M,S,D;
        scanf("%d %d %d %d",&N,&M,&S,&D);
        //N城市个数 M高速公路条数 S出发地编号 D目的城市编号 
        for(int i=0;i<N;++i){
            for(int j=0;j<N;j++){
                G[i][j]=INF;
                p[i][j]=INF;
            }
        }
        //初始化最短距离和收费额二维数组,当然用一个三维数组p[N][N][2]也是可以的 
        int c1,c2,ml,pay;
        for(int i=0;i<M;i++){
            scanf("%d %d %d %d",&c1,&c2,&ml,&pay);
            G[c1][c2]=G[c2][c1]=ml;//输入两个城市之间的高速公路距离 
            p[c1][c2]=p[c2][c1]=pay;//输入两个城市高速公路的收费额 
        }
        for(int k=0;k<N;k++){//用Floyd算法计算最短距离 
            for(int i=0;i<N;i++){
                for(int j=0;j<N;j++){
                    if(i!=j&&j!=k){
                        if((G[i][k]+G[k][j])<G[i][j]){
                            G[i][j]=G[i][k]+G[k][j];
                            p[i][j]=p[i][k]+p[k][j];//上述第一种情况 
                        }
                        else if(((G[i][k]+G[k][j])==G[i][j])&&((p[i][k]+p[k][j])<p[i][j])){
                            p[i][j]=p[i][k]+p[k][j];
                        }
                    }
                }
            }
        }
        printf("%d",G[S][D],p[S][D]); 
    } 
    
    2.其他问题:

    对于图的知识点,算法较多,很容易混杂 ,就上述的算法中刚开始可以分辨清楚,多了起来之后,就会混杂在一起。可能是自我概念还比较模糊,会继续加强概念的巩固。

  • 相关阅读:
    HDU 1525
    kmp模板
    hdu 4616 Game(树形DP)
    hdu 4619 Warm up 2(并查集活用)
    hdu 4614 Vases and Flowers(线段树加二分查找)
    Codeforces 400D Dima and Bacteria(并查集最短路)
    poj 2823 Sliding Window (单调队列)
    hdu 2196 Computer(树形dp)
    hdu 4604 Deque
    最短路径
  • 原文地址:https://www.cnblogs.com/hcy420/p/12905467.html
Copyright © 2011-2022 走看看