zoukankan      html  css  js  c++  java
  • DS博客作业04--图

    0.PTA得分截图

    1.本周学习总结

    1.1 总结图内容

    图的存储结构:邻接表和邻接矩阵

    邻接矩阵及其特点


    1.无向图的邻接矩阵是对称的,有向图的可能是不对称的
    2.对角线上的点的值都为0
    3.时间复杂度和空间复杂度都为O(n^2)
    4.在无向图中,统计第i行(列)1的个数可得顶点i的度。
    在有向图中,统计第i行1的个数可得顶点i的出度OD;统计第j列1的个数可得顶点j的入度ID;
    5.一个图的邻接矩阵是唯一的

    邻接表及其特点


    1.每条链上的其他节点都与头节点相连
    2.下边为i的元素表示顶点为i的表头节点
    3.图的邻接表存储方法是一种顺序分配与链式分配相结合的存储方法。 
    4.一个图的邻接表是不唯一的

    邻接表存储类型定义:                                          邻接矩阵存储类型:
    typedef struct ANode                                        typedef struct
    {                                                           {
        int adjvex;     //该边的终点边号                              int edges[MAXV][MAXV];//邻接矩阵
        struct ANode*nextarc;  //指向下条边的指针                     int n,e;
        int info;    //权值                                      }AdjGraph;
    }ArcNode;
    typedef struct Vnode
    {
        int data;//顶点
        ArcNode* firstarc;//指向第一条边
    }VNode;
    typedef VNode Adjlist[MAXV];
    typedef struct
    {
       Adjlist adjlist;//邻接表
       int n,e;
    }AdjGraph;
    

    图的遍历及其应用

    深度遍历
    含义:首先访问初始顶点v,选择一个与初始顶点相邻且没被访问过的顶点w,再从w进行深度搜索,直到所有顶点都被访问
    邻接表深度遍历                                    邻接矩阵深度遍历
    void DFS(AdjGraph* G, int v)                     void DFS(MGraph g, int v)
    {                                                {
    	ArcNode* p;                                    visited[v]=1;                          
    	visited[v] = 1;                                cout<<v;
            cout<<v;                                       
                                                           for(int j=1;j<=g.n;j++)
    	p = G->adjlist[v].firstarc;                        if(g.edges[v][j]!=0&&visited[j]==0)
    	while (p != NULL)                                      DFS(g,j);
    	{                                       }
    		if (visited[p->adjvex] == 0)
    			DFS(G, p->adjvex);
    		p = p->nextarc;
    	}
    }
    
    判断从u到v是否有路径                                          输出从u到v的路径
    void ExistPath(AGraph*G,int u,int v,bool&has)               void FindaPath(AGraph*G,int u ,int v,int path[],int d)
    {                                                           {
        ArcNode*p;                                                   ArcNode*p;int i;
        visited[u]=1;                                                visited[u]=1;d++;
        if(u==v)                                                     path[d]=u;
        {                                                            if(u==v)
           has=true;                                                 {
           return;                                                       cout<<"一条路径为:";
         }                                                               for(i=0;i<=d;i++)
         p=G.adjlist[u].firstarc;                                           cout<<path[i];                               
         while(p!=NULL)                                                  return;
         {                                                           }
             if(visited[p->adjvex]==0)                               p=G.adjlist[u].firstarc;                   
                ExistPath(G,p->adjvex,v,has);                        while(p!=NULL)    
             p=p->nextarc;                                           {
          }                                                                if(visited[p->adjvex]==0) 
    }                                                                           ExistPath(G,p->adjvex,v,path,d);
                                                                           p=p->nextarc;
                                                                      }
                                                                 }
    最短路径                                                      判断图是否连通
    void ShortPath(AdjGraph *G,int u,int v)                      int judge(AGraph g)
    {                                                            {
           qu[rear].data=u;//第一个顶点u进队                          for(int i=0;i<g.n;i++)
            while (front!=rear)//队不空循环                              visited[i]=0;
            {      front++;		                                 DFS(G,0)
                   w=qu[front].data;                                 for(int i=0;i<g.n;i++)          
                  if (w==v)   根据parent关系输出路径break;                if(!visited[i])//有节点没访问
                  while(遍历邻接表)                                         return 0;
                    {         rear++;                             }
    	          qu[rear].data=p->adjvex;
                              qu[rear].parent=front;
    	 }
             }	      
    }
    

    最小生成树相关算法及应用

    概念:一个连通图的生成树是一个极小连通子图,它含有图中全部n个顶点和构成一棵树的(n-1)条边。不能回路。  
    prime算法求最小生成树
    (1)初始化U={v}。v到其他顶点的所有边为候选边;
    (2)重复以下步骤n-1次,使得其他n-1个顶点被加入到U中:
    1.从候选边中挑选权值最小的边输出,设该边在V-U中的顶点是k,将k加入U中;
    2.考察当前V-U中的所有顶点j,修改候选边:若(j,k)的权值小于原来和顶点k关联的候选边,则用(k,j)取代后者作为候选边。

    克鲁斯卡尔算法求最小生成树
    (1)置U的初值等于V(即包含有G中的全部顶点),TE的初值为空集(即图T中每一个顶点都构成一个连通分量)。
    (2)将图G中的边按权值从小到大的顺序依次选取:
    1.若选取的边未使生成树T形成回路,则加入TE;
    2. 否则舍弃,直到TE中包含(n-1)条边为止。
    Kruskal算法

    最短路径相关算法及应用

    用迪杰斯特拉(Dijkstra)算法求最短路径

    初始化dist数组、path数组、s数组
    遍历图中所有节点
     {
           for(i=0;i<g.n;i++) //找最短dist
               { 
                 若s[i]!=0,则dist数组找最短路径,顶点为u
                }
              s[u]=1  //加入集合S,顶点已选
            for(i=0;i<g.n;i++)  //修正dist
               { 
                 若s[i]!=0 && dist[i]>dist[u]+g.edges[u][i]
                  则修正dist[i]= dist[i]>dist[u]+g.edges[u][i]
                       path[i]=u;
                }
     }
    
    1.从T中选取一个其距离值为最小的顶点W, 加入S
    2.S中加入顶点w后,对T中顶点的距离值进行修改:
    若加进W作中间顶点,从V0到Vj的距离值比不加W的路径要短,则修改此距离值;
    3.重复上述步骤1,直到S中包含所有顶点,即S=V为止。
    

    图像表示如下

    用佛洛依德(Floyd)算法求最短路径

    void Floyd(Graph g)
    {
            建立A数组和path数组,A[MAXV][MAXV],path[MAXV][MAXV];
            for i=0 to g.n;
                for j=0 to g.n
                {
                     A和path数组初始化;
                }
           for k=0 to g.n
                for i=0 to g.n
                      for j=0 to g.n
                            if(A[i][j]>A[i][k]+A[k][j])//找到更短路径
                            {
                                      修改路径长度;
                                      path[i][j]=k;
                            }
    }
    

    拓扑排序、关键路径

    拓扑排序:在一个有向图中找一个拓扑序列的过程称为拓扑排序。

    1.从有向图中选取一个没有前驱的顶点,并输出之;
    2.从有向图中删去此顶点以及所有以它为尾的弧;
    3.重复上述两步,直至图空,或者图不空但找不到无前驱的顶点为止。
    
    typedef struct
    { 
       int data;
       int count;    //存放顶点入度
       ArcNode* firstarc;
    }VNode;
    void TopSort(AdjGraph*G)
    {
          遍历邻接表
                 计算每个顶点的入度,存入头结点count成员
          遍历图顶点
                若发现入度为0顶点,入栈st
          while(栈不空)
          {
                  出栈节点v,访问。
                 遍历v的所有邻接点
                 {    
                       所有邻接点的入度-1  
                       若有邻接点入度为0,则入栈st
                 }
          }
    }
    
    void topSort(AdjMGraph* G)   //拓扑排序算法
    {
         int i,j;
         int St[MAXV];
         int top=-1;
         ArcNode*p;
         for(i=0;i<G.n;i++)
            G->adjlist[i].count=0;
         for(i=0;i<G.n;i++)       //求顶点入度
         {
               p=G->adjlist[i].firstarc;
               while(p!=NULL)
               {
                    G->adjlist[p->adjvex]++;
                    p=p->nextarc;
               }
         }
         for(i=0;i<G.n;i++)   //将入度为0的进栈
            if(G->adjlist[i].count==0)
            {
                 top++;
                 St[top]=i;
            }
         while(top>-1)
         {
             i=St[top];
             top--;
             cout<<i;
             p=G->adjlist[i].firstarc;
             while(p!=NULL)
             {
                  j=p->adjvex;
                  G->adjlist[j].count--;//出边邻接点的入度减1
                  if(G->adjlist[j].count==0)//减1后若入度为0进栈
                  {
                         top++;
                         St[top]=j;
                  }
                  p=p->nextarc;
             }
         }
    }
    

    关键路径

    1.关键路径为原点到汇点的最长路径
    2.ve为事件的最早开始时间,vl为事件的最迟开始时间
    过程如下:

    • 求拓扑序列
    • 按拓扑序列求ve数组
    • 按拓扑序列和ve数组求vl数组
    • 计算边的最早和最迟时间,即e和l
    • 找e=l边即为关键活动,边连起来即为关键路径

    1.2.谈谈你对图的认识及学习体会。

    • 图需要记住的专业术语比较多,如连通分量,图,有向图和无向图等
    • 图的算法很多,而且难度也挺大的,代码量都比较大
    • 图的存储结构也是目前学的最复杂的了,邻接表的存储结构需要多个结构体
    • 感觉图的编程题比较更接近实际生活问题了,例如村村通和旅游规划,这类题目实际性强,比较有趣
    • 图的代码比较难理解,需要在编程过程中理解,看是很难记住的

    2.阅读代码

    2.1 题目及解题代码


    2.1.1 该题的设计思路

    用二维数组dp来存储答案,利用小机器人只能往右或者往下,那么dp[i][j]的值就是第 i 行第 j 列这个格子的上面那
    个格子的值加上左边那个格子的值,也就是dp[i][j] = dp[i-1][j] + dp[i][j-1],因为这两个格子都可以走到
    dp[i][j]这个格子,那么他们的路径数之和就是dp[i][j]的值。

    2.1.2 该题的伪代码

    2.1.3 运行结果

    运行结果与题目所给答案一致

    2.1.4分析该题目解题优势及难点。

    解题优势:利用数学规律和题目所给的机器人行走方式进行解题,利用当前的路径条数等于左边格子的路径加上边格子的路径
    即dp[i][j] = dp[i-1][j] + dp[i][j-1],将复杂问题通过规律简化

    难点:解题思路很难,因为如果直观地要求到达指定格子的路径条数是非常复杂的,格子越多越复杂,因此只能想办法找出规律

    2.2 题目及解题代码


    2.2.1 该题的设计思路

    从每个小岛出发,周围的格子距离加1,最后到达的海域的距离即为所求

    2.2.2 该题的伪代码

    2.2.3 运行结果

    2.2.4分析该题目解题优势及难点。

    解题优势:思路比较好理解,运用队列来辅助搜索
    难点:对于图的遍历要非常熟悉,要灵活运用广度搜索

    2.3 题目及解题代码



    2.3.1 该题的设计思路

    1.使用Floyd算法求出各个城市到其它城市的距离,保存在矩阵D[n][n]中。
    2.遍历D[n][n],统计各个城市在距离不超过 distanceThreshold 的情况下,能到达的其它城市的数量。
    3.返回能到达其它城市最少的城市

    2.3.2 该题的伪代码

    2.3.3 运行结果

    2.3.4分析该题目解题优势及难点。

    解题优势:运用Floyd算法求出最短路径来进行解题
    难点:题目意思比较难懂,需要比较好的逻辑思维和对Floyd算法掌握的比较熟悉

  • 相关阅读:
    Ethical Hacking
    Ethical Hacking
    Ethical Hacking
    National Treasures HDU
    Matrix HDU
    过山车 HDU
    Jimmy’s Assignment HDU
    Card Game Cheater HDU
    Uncle Tom's Inherited Land* HDU
    50 years, 50 colors HDU
  • 原文地址:https://www.cnblogs.com/sym2446/p/12828112.html
Copyright © 2011-2022 走看看