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

    这个作业属于哪个班级 数据结构--网络2011/2012
    这个作业的地址 DS博客作业04--图
    这个作业的目标 学习图结构设计及相关算法
    姓名 唐宇悦

    0.PTA得分截图

    1.本周学习总结

    1.1 图的存储结构

    1.1.1 邻接矩阵

    有向图:

    网:

    邻接矩阵的结构体定义

    #define MaxVertexNum 100;	//顶点数目的最大值
    typedef char VertexType;	//顶点的数据类型
    typedef int EdgeType;	//带权图中边上权值的数据类型
    typedef struct{
    	VertexType Vex[MaxVertexNum];	//顶点表
    	EdgeType Edge[MaxVertexNum][MaxVertexNum];	//邻接矩阵,边表
    	int vexnum, arcnum;	//图的当前顶点数和弧树
    }MGraph;
    

    建图函数

    void CreateMGraph(MGraph &g, int n, int e)//建图 
    {
    	//n顶点,e弧数
    	g.n = n;
    	g.e = e;
    	int i, j;
    	int a, b;//下标
    	for (i = 1; i <= n; i++)//先进行初始化
    	{
    		for (j = 1; j <= n; j++)
    		{
    			g.edges[i][j] = 0;
    		}
    	}
    	for (i = 1; i <= e; i++)//无向图
    	{
    		cin >> a >> b;
    		g.edges[a][b] = 1;
    		g.edges[b][a] = 1;
    	}
    }
    

    图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息。
    设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为:

    看一个实例,下图左就是一个无向图。

    从上面可以看出,无向图的边数组是一个对称矩阵。所谓对称矩阵就是n阶矩阵的元满足aij = aji。即从矩阵的左上角到右下角的主对角线为轴,右上角的元和左下角相对应的元全都是相等的。
    从上面可以看出,无向图的边数组是一个对称矩阵。所谓对称矩阵就是n阶矩阵的元满足aij = aji。即从矩阵的左上角到右下角的主对角线为轴,右上角的元和左下角相对应的元全都是相等的。
    从这个矩阵中,很容易知道图中的信息。
    (1)要判断任意两顶点是否有边无边就很容易了;
    (2)要知道某个顶点的度,其实就是这个顶点vi在邻接矩阵中第i行或(第i列)的元素之和;
    (3)求顶点vi的所有邻接点就是将矩阵中第i行元素扫描一遍,arc[i][j]为1就是邻接点;
    而有向图讲究入度和出度,顶点vi的入度为1,正好是第i列各数之和。顶点vi的出度为2,即第i行的各数之和。

    1.1.2 邻接表


    邻接表的结构体定义

    #define MAXVEX 100;	//图中顶点数目的最大值
    type char VertexType;	//顶点类型应由用户定义
    typedef int EdgeType;	//边上的权值类型应由用户定义
    /*边表结点*/
    typedef struct EdgeNode{
    	int adjvex;	//该弧所指向的顶点的下标或者位置
    	EdgeType weight;	//权值,对于非网图可以不需要
    	struct EdgeNode *next;	//指向下一个邻接点
    }EdgeNode;
    
    /*顶点表结点*/
    typedef struct VertexNode{
    	Vertex data;	//顶点域,存储顶点信息
    	EdgeNode *firstedge	//边表头指针
    }VertexNode, AdjList[MAXVEX];
    
    /*邻接表*/
    typedef struct{
    	AdjList adjList;
    	int numVertexes, numEdges;	//图中当前顶点数和边数
    }
    

    建图函数

    void CreateAdj(AdjGraph *&G, int n, int e)//创建图邻接表
    {
    	int i, j, a, b;
    	G = new AdjGraph;
    	for (i = 1; i <= n; i++)//邻接表头结点置零
    	{
    		G->adjlist[i].firstarc = NULL;
    	}
    	for (j = 1; j <= e; j++)//无向图
    	{
    		cin >> a >> b;	
    		ArcNode *p,*q;
    		p = new ArcNode;
    		q = new ArcNode;
    		p->adjvex = b;//用头插法进行插入
    		q->adjvex = a;
    		p->nextarc = G->adjlist[a].firstarc;
    		G->adjlist[a].firstarc = p;
    		q->nextarc = G->adjlist[b].firstarc;
    		G->adjlist[b].firstarc = q;
    	}
    	G->n = n;
    	G->e = e;
    }
    

    邻接矩阵是不错的一种图存储结构,但是,对于边数相对顶点较少的图,这种结构存在对存储空间的极大浪费。因此,找到一种数组与链表相结合的存储方法称为邻接表。
    邻接表的处理方法是这样的:
    (1)图中顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过,数组可以较容易的读取顶点的信息,更加方便。
    (2)图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以,用单链表存储,无向图称为顶点vi的边表,有向图则称为顶点vi作为弧尾的出边表。
    例如,下图就是一个无向图的邻接表的结构。

    从图中可以看出,顶点表的各个结点由data和firstedge两个域表示,data是数据域,存储顶点的信息,firstedge是指针域,指向边表的第一个结点,即此顶点的第一个邻接点。边表结点由adjvex和next两个域组成。adjvex是邻接点域,存储某顶点的邻接点在顶点表中的下标,next则存储指向边表中下一个结点的指针。

    1.1.3 邻接矩阵和邻接表表示图的区别

    对于一个具有n个顶点e条边的无向图
    它的邻接表表示有n个顶点表结点2e个边表结点
    对于一个具有n个顶点e条边的有向图
    它的邻接表表示有n个顶点表结点e个边表结点
    如果图中边的数目远远小于n2称作稀疏图,这是用邻接表表示比用邻接矩阵表示节省空间;
    如果图中边的数目接近于n2,对于无向图接近于n*(n-1)称作稠密图,考虑到邻接表中要附加链域,采用邻接矩阵表示法为宜。

    • 时间复杂度
      用邻接矩阵构造图时,若存储的是一个无向图,则时间复杂度为O(n^2 + n*e),其中,对邻接矩阵的初始化耗费的时间为O(n^2);
      对于DFS,BFS遍历来说,时间复杂度和存储结构有关:
      n表示有n个顶点,e表示有e条边。

    1.若采用邻接矩阵存储,

    时间复杂度为O(n^2);

    2.若采用邻接链表存储,建立邻接表或逆邻接表时,

    若输入的顶点信息即为顶点的编号,则时间复杂度为O(n+e);
    若输入的顶点信息不是顶点的编号,需要通过查找才能得到顶点在图中的位置,则时间复杂度为O(n*e);

    1.2 图遍历

    1.2.1 深度优先遍历

    ⑴ 访问顶点v;
    ⑵ 从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;
    ⑶ 重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。
    首先,我们访问V1结点,V1结点入栈并输出,然后发现V1与V2相连,因此我们将V2入栈,同理,V4和V5也入栈输出,因此遍历序列为V1 V2 V4 V5

    接下来,V5入栈输出后,我们发现与V5相连的两个结点都已经访问过了,因此V5直接出栈,返回到了上一层,即V4,在V4结点处我们发现还有一个结点V8没有被访问到,因此将V8入栈并输出

    同理,V8入栈后会直接出栈,因为与V8相邻的结点都已经被访问过了,接下来V4、V2也出栈,只留下了V1在堆栈中

    这时我们会发现,V1还有结点没有访问到!所以V3、V6、V7相继入栈并输出

    最后依次出栈,深度优先就遍历完了.
    深度遍历代码

    /**********深度优先遍历*********/
    int visitDFS[maxSize];
    void DFS(MGraph G,int i)
    {
    	int j;
    	visitDFS[i] = 1;
    	printf("%d ", G.Vex[i]);
    	for (j = 0; j < G.vexnum; j++)
    	{
    		if (G.Edge[i][j] != 32767 && !visitDFS[j])
    			DFS(G, j);
    	}
    }
     
    void DFSTraverse(MGraph G)
    {
    	int i;
    	for (i = 0; i < G.vexnum; i++)
    		visitDFS[i] = 0;
    	for (i = 0; i < G.vexnum; i++)
    	{
    		if (!visitDFS[i])
    			DFS(G, i);
    	}
    
    

    深度遍历适用哪些问题的求解
    1.求无向图的连通分量的个数
    2.连通分量都包含哪些顶点
    3.两个顶点是否在同一个连通分量中
    4.单源路径问题
    5.检测无向图中的环

    1.2.2 广度优先遍历

    在最开始时,V1入列,然后出列输出

    紧接着,与V1相连的结点有V2和V3,因此V2和V3入列并输出

    接下来V2出列,与V2相连的结点有V4和V5,所以V4和V5入列并输出

    接下来同理,V3出列,V6和V7入列并输出

    然后V4出列,与V4相连的还有V8,所以V8入列并输出

    这样就遍历完了,后面的结点由于相邻结点都被访问过了,因此可以直接出列。
    广度遍历代码

    //广度优先遍历
    int visitBFS[maxSize];
    void BFS(MGraph G)
    {
    	int i, j;
    	Queue Q;
    	for (i = 0; i < G.vexnum; i++)
    		visitBFS[maxSize] = 0;
    	InitQueue(&Q);
    	for (i = 0; i < G.vexnum; i++)
    	{
    		if (!visitBFS[i])
    		{
    			visitBFS[i] = 1;
    			printf("%d ", G.Vex[i]);
    			EnQueue(&Q, i);
     
    			while (!IsEmpty(&Q))
    			{
    				DeQueue(&Q, &i);
    				for (j = 0; j < G.vexnum; j++)
    				{
    					if (!visitBFS[j] && G.Edge[i][j] != 32767)
    					{
    						visitBFS[j] = 1;
    						printf("%d ", G.Vex[j]);
    						EnQueue(&Q, j);
    					}
    				}
    			}
    		}
    	}
    }
    

    广度遍历适用哪些问题的求解。
    BFS 的应用一:层序遍历
    BFS 的应用二:最短路径

    1.3 最小生成树

    用自己语言描述什么是最小生成树。
    我认为最小生成树就是边的权值最小的生成树

    1.3.1 Prim算法求最小生成树


    基于上述图结构求Prim算法生成的最小生成树的边序列

    Prim算法思想:
    逐渐长成一棵最小生成树。假设G=(V,E)是连通无向网,T=(V,TE)是求得的G的最小生成树中边的集合,U是求得的G的最小生成树所含的顶点集。初态时,任取一个顶点u加入U,使得U={u},TE=Ø。重复下述操作:找出U和V-U之间的一条最小权的边(u,v),将v并入U,即U=U∪{v},边(u,v)并入集合TE,即TE=TE∪{(u,v)}。直到V=U为止。最后得到的T=(V,TE)就是G的一棵最小生成树。也就是说,用Prim求最小生成树是从一个顶点开始,每次加入一条最小权的边和对应的顶点,逐渐扩张生成的。

    实现Prim算法的2个辅助数组是什么?其作用是什么?Prim算法代码。
    设置2个辅助数组:
    1.closest[i]:最小生成树的边依附在U中顶点编号。
    2.lowcost[i]表示顶点i(i ∈ V-U)到U中顶点的边权重,取最小权重的顶点k加入U。
    并规定lowcost[k]=0表示这个顶点在U中

    每次选出顶点k后,要队lowcost[]和closest[]数组进行修正

    //最小生成树-Prim算法 
    void Prim(Graph G)
    {
    	int v=0;//初始节点
    	closedge C[MaxVerNum];
    	int mincost = 0; //记录最小生成树的各边权值之和
    	//初始化
    	for (int i = 0; i < G.vexnum; i++)
    	{
    		C[i].adjvex = v;
    		C[i].lowcost = G.Edge[v][i];
    	}
    	cout << "最小生成树的所有边:"<< endl;
    	//初始化完毕,开始G.vexnum-1次循环
    	for (int i = 1; i < G.vexnum; i++)
    	{
    		int k;
    		int min = INF;
    		//求出与集合U权值最小的点 权值为0的代表在集合U中
    		for (int j = 0; j<G.vexnum; j++)
    		{
    			if (C[j].lowcost != 0 && C[j].lowcost<min)
    			{
    				min = C[j].lowcost;
    				k = j;
    			}
    		}
    		//输出选择的边并累计权值
    		cout << "(" << G.Vex[k] << "," << G.Vex[C[k].adjvex]<<") ";
    		mincost += C[k].lowcost;
    		//更新最小边
    		for (int j = 0; j<G.vexnum; j++)
    		{
    			if (C[j].lowcost != 0 && G.Edge[k][j]<C[j].lowcost)
    			{   
    				C[j].adjvex = k;
    				C[j].lowcost= G.Edge[k][j];
    			}
    		}
     
    	}
    	cout << "最小生成树权值之和:" << mincost << endl;
    
    

    分析Prim算法时间复杂度,适用什么图结构?
    Prim算法的时间复杂度是O(n^2)的,因此适用于稠密图的最小生成树

    1.3.2 Kruskal算法求解最小生成树

    基于上述图结构求Kruskal算法生成的最小生成树的边序列
    首先,在初始状态下,对各顶点赋予不同的标记(用颜色区别),如下图所示:

    对所有边按照权值的大小进行排序,按照从小到大的顺序进行判断,首先是(1,3),由于顶点 1 和顶点 3 标记不同,所以可以构成生成树的一部分,遍历所有顶点,将与顶点 3 标记相同的全部更改为顶点 1 的标记,如下图所示:

    其次是(4,6)边,两顶点标记不同,所以可以构成生成树的一部分,更新所有顶点的标记为:

    其次是(2,5)边,两顶点标记不同,可以构成生成树的一部分,更新所有顶点的标记为

    然后最小的是(3,6)边,两者标记不同,可以连接,遍历所有顶点,将与顶点 6 标记相同的所有顶点的标记更改为顶点 1 的标记:

    继续选择权值最小的边,此时会发现,权值为 5 的边有 3 个,其中(1,4)和(3,4)各自两顶点的标记一样,如果连接会产生回路,所以舍去,而(2,3)标记不一样,可以选择,将所有与顶点 2 标记相同的顶点的标记全部改为同顶点 3 相同的标记:

    选取的边的数量相比与顶点的数量小 1 时,说明最小生成树已经生成
    实现Kruskal算法的辅助数据结构是什么?其作用是什么?Kruskal算法代码。
    实现Kruskal算法的辅助数据结构是vset[]。vset[]用于判断顶点i,j是否属于同一个连通分量。

    //最小生成树-Kruskal算法
    void Kruskal(Graph G)
    {
    	//初始化
    	sort(l.begin(), l.end(),cmp);
    	int verSet[MaxVerNum];
    	int mincost = 0;
    	for (int i = 0; i < G.vexnum; i++)
    		verSet[i] = i;
    	cout << "最小生成树所有边:" << endl;
    	//依次查看边
    	int all = 0;
    	for (int i = 0; i < G.arcnum; i++)
    	{
    		if (all == G.vexnum - 1)break;
    		int v1 = verSet[l[i].from];
    		int v2 = verSet[l[i].to];
    		//该边连接两个连通分支
    		if (v1 != v2)
    		{
    			cout << "(" << l[i].from << "," << l[i].to << ") ";
    			mincost += l[i].weight;
    			//合并连通分支
    			for (int j = 0; j < G.vexnum; j++)
    			{
    				if (verSet[j] == v2)verSet[j] = v1;
    			}
    			all++;
    		}
    	}
    	cout << "最小生成树权值之和:" <<mincost<<endl;
    
    

    分析Kruskal算法时间复杂度,适用什么图结构?
    时间复杂度为O(eloge)。和普里姆算法恰恰相反,更适合于求稀疏图的最小生成树。

    1.4 最短路径

    1.4.1 Dijkstra算法求解最短路径

    迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。
    它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止
    基于上述图结构,求解某个顶点到其他顶点最短路径。(结合dist数组、path数组求解)
    1.狄克斯特拉(Dijkstra)算法
    过程:
    S={入选顶点集合,初值V0},T={未选顶点集合}。
    若存在<V0,Vi>,距离值为<V0,Vi>弧上的权值
    若不存在<V0,Vi>,距离值为∞
    从T中选取一个其距离值为最小的顶点W, 加入S
    S中加入顶点w后,对T中顶点的距离值进行修改:重复上述步骤1,直到S中包含所有顶点,即S=V为止。
    重复上述步骤1,直到S中包含所有顶点,即S=V为止。
    图解:

    Dijkstra算法需要哪些辅助数据结构

    void Dijkstra(MGraph g, int v)//源点v到其他顶点最短路径 
    {
    	int dist[MAXV], path[MAXV],s[MAXV];
    	int mindistance,u;//u为每次所选最短路径点
    
    	for (int i = 0; i < g.n; i++)//初始化各数组
    	{
    		s[i] = 0;//初始已选入点置空
    		dist[i] = g.edges[v][i];//初始化最短路径
    
    		if (dist[i] < INF) path[i] = v;
    		else path[i] = -1;//即无直接到源点V的边,因此初始化为-1
    	}
    	s[v] = 1;//源点入表示已选
    
    	for (int j = 0; j < g.n; j++)//要将所有点都选入需循环n-1次
    	{
    		mindistance = INF;//每次选之前重置最短路径
    		for (int i = 1; i < g.n; i++)//每次都遍历源点以外其他点来选入点
    		{
    			if (s[i] == 0 && dist[i] < mindistance)//在未选的点中找到最短路径
    			{
    				mindistance = dist[i];
    				u = i;//u记录选入点
    			}
    		}
    		s[u] = 1;//最后记录的u才为最后选入点
    
    		for (int i = 1; i < g.n; i++)//修正数组值
    		{
    			if (s[i] == 0)//!!仅需修改未被选入点的,已选入的既定
    			{
    				if (g.edges[u][i] < INF && dist[u] + g.edges[u][i] < dist[i])//先判断选入点到与该点存在时再比较判断
    				{
    					dist[i] = dist[u] + g.edges[u][i];
    					path[i] = u;
    				}
    			}
    		}
    	}
    	Dispath(dist, path, s, g.n, v);
    
    }
    

    Dijkstra算法的时间复杂度,使用什么图结构,为什么?
    Dijkstra算法 适用于求 稠密图 的最短路问题,因为 稠密图 的边数远远大于点数,Dijkstra算法的思路为进行 n 次循环,每次循环再遍历 n 个点确定一个还未确定最短距离的点中距离源点最近距离的点,然后再用这个点更新其所能到达的点(算法默认当前的点可以到达所有的点,因为没有到达的点之间的距离都已经初始化为正无穷大,所以不会被更新,不影响结果)。时间复杂度为 O(n2)。

    1.4.2 Floyd算法求解最短路径

    Floyd算法解决什么问题?
    Floyd算法(Floyd-Warshall algorithm)又称为弗洛伊德算法、插点法,是解决给定的加权图中顶点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。
    Floyd算法需要哪些辅助数据结构

    void Floyd(Graph G)		
    {     
        int A[MAXVEX][MAXVEX];	//建立A数组
        int path[MAXVEX][MAXVEX];	//建立path数组
        int i, j, k;
       for (i=0;i<G.n;i++)   		
           for (j=0;j<G.n;j++) 
           {       
              A[i][j]=G.edges[i][j];
    	 if (i!=j && G.edges[i][j]<INF)
    	      path[i][j]=i; 	//i和j顶点之间有一条边时
           else			 
    	      path[i][j]=-1;
           }
    
      for (k=0;k<G.n;k++)		//求Ak[i][j]
     {     
         for (i=0;i<G.n;i++)
           for (j=0;j<G.n;j++)
    	    if (A[i][j]>A[i][k]+A[k][j])	//找到更短路径
    	    {   
                    A[i][j]=A[i][k]+A[k][j];	//修改路径长度
    	       path[i][j]=path[k][j]; 	//修改最短路径为经过顶点k
              }
      }
    }	
    1.两个二维数组
    2.邻接矩阵
    

    Floyd算法优势
    Floyd算法适用于APSP(AllPairsShortestPaths),是一种动态规划算法,稠密图效果最佳,边权可正可负。此算法简单有效,由于三重循环结构紧凑,对于稠密图,效率要高于执行|V|次Dijkstra算法。
    优点:容易理解,可以算出任意两个节点之间的最短距离,代码编写简单
    缺点:时间复杂度比较高,不适合计算大量数据。

    1.5 拓扑排序

    拓扑排序指的是将有向无环图(又称“DAG”图)中的顶点按照图中指定的先后顺序进行排序。
    找一个有向图,并求其对要的拓扑排序序列

    对有向无环图进行拓扑排序,只需要遵循两个原则:
    1.在图中选择一个没有前驱的顶点 V;
    2.从图中删除顶点 V 和所有以该顶点为尾的弧。

    进行拓扑排序时,首先找到没有前驱的顶点 V1,如图 2(1)所示;在删除顶点 V1 及以 V1 作为起点的弧后,继续查找没有前驱的顶点,此时, V2 和 V3 都符合条件,可以随机选择一个,例如图 2(2) 所示,选择 V2 ,然后继续重复以上的操作,直至最后找不到没有前驱的顶点。
    所以,针对图 2 来说,拓扑排序最后得到的序列有两种:

    • V1 -> V2 -> V3 -> V4
    • V1 -> V3 -> V2 -> V4
      实现拓扑排序代码,结构体如何设计?
    typedef struct {
    	Vertex data;//顶点信息
    	int count;//存放入度
    	AreNode *firstarc;//头结点类型
    }VNode;
    

    书写拓扑排序伪代码,介绍拓扑排序如何删除入度为0的结点?

    while(栈不空)
    {
       出栈v,访问;
       遍历v所有邻接点
       {
          所有邻接点的入度-1
          当入度为0时,则入栈,以此实现入度为0时的删除操作
       }
    }
    

    如何用拓扑排序代码检查一个有向图是否有环路?
    DFS判断有向图是否有环
    对一个节点u进行DFS,判断是否能从u回到自己这个节点,即是否存在u到u的回路。
    color数组代表每个节点的状态
    -1代表还没访问,0代表正在被访问,1代表访问结束
    如果一个状态为0的节点,与它相连的节点状态也为0,则有环

    1.6 关键路径

    什么叫AOE-网?

    AOE网(Activity On Edge)即边表示活动的网,是与AOV网(顶点表示活动)相对应的一个概念。而拓扑排序恰恰就是在AOV网上进行的,这是拓扑排序与关键路径最直观的联系。AOE网是一个带权的有向无环图,其中顶点表示事件(Event),弧表示活动,权表示活动持续的时间。

    什么是关键路径概念?

    在项目管理中,关键路径是指网络终端元素的元素的序列,该序列具有最长的总工期并决定了整个项目的最短完成时间。
    求关键路径必须在拓扑排序的前提下进行,有环图不能求关键路径;   (2) 只有缩短关键活动的工期才有可能缩短工期;   (3) 若一个关键活动不在所有的关键路径上,减少它并不能减少工期;   (4) 只有在不改变关键路径的前提下,缩短关键活动才能缩短整个工期。

    什么是关键活动?

    关键活动是为准时完成项目而必须按时完成的活动。即处于关键路径上的活动。所有项目都是由一系列活动组成,而在这些活动中存在各种链接关系和活动约束。其中有些活动如果延误就会影响整个项目工期。在项目中总存在这样一类直接影响项目工期变化的活动,这些活动就是关键活动。

    2.PTA实验作业

    2.1 六度空间


    2.1.1 伪代码

    宏定义邻接矩阵g[10001][10001],顶点数v,边数e,循环变量i,中间变量x,y用来输入
    main函数
       定义浮点型数据 n,m来求最后所占比率
       输入顶点数v和边数e
       while e--   //构建邻接矩阵
            输入边关系 x y
            g[x][y] = g[y][x] = 1
       end while
       for i=1 to v do
            n=v  
            m=bfs(i) //调用bfs函数
       end for
       return 0
    
    int bfs(int z)
       定义数组vis[10001]=0 表示是否被访问过的结点
       定义 last = z表示记录每层的最后一个元素
       i定义tail表示用于记录每一层压入栈时的结点
       定义 level = 0 表示与该结点距离是否为6
       定义count=1//表示结点
       创建int型栈q并入栈z
       将vis[z]置为1表示访问过了
       while q不为空 
          	z = q.front()//取栈顶元素于z
    	q.pop()//去栈顶
    	for i = 1to v do //广度遍历方法
    		if g[z][i] 等于1 并且 vis[i]等于 0 then
    				count++;
    				vis[i] = 1;
    				q.push(i);
    				tail = i;
    		end if 
             end for 
    	if last 等于z then//一层全部从栈弹出,准备开始弹下一层,弹出的数等于当前层最后一个元素,并记录与last 
    		level++;
    		last = tail;//记录最后一个元素 
            end if 
    		if  level 等于 6 break //符合题意的路径节点       
        return count
    

    2.1.2 提交列表

    2.1.3 本题知识点

    1.图的广度遍历方法
    2.栈的方法
    3.使用了创建邻接矩阵方法

    2.2 村村通


    2.2.1 伪代码

    用边存储结构读取数据
    初始化vset数组使各数的起始节点设为本身
    while k记录已保存的边数目!=顶点数-1
          寻找权值最小的边
          if 该边的权值为极大值
                图不连通 输出-1并退出循环
          寻找这边始末节点的起始节点
          if 起始节点不相等
                将其中一边的起始节点的起始节点记录为另一边的起始节点
                记录权值
          将该边的权值设为极大值
    if 记录的边数=顶点数-1
          输出权值的和
    

    2.2.2 提交列表

    2.2.3 本题知识点

    1.利用了prim最小生成树方法
    2.邻接矩阵用法

  • 相关阅读:
    hdu 3018
    poj 1833 排列
    poj 1256 Anagram
    CF 548B Mike and Fun
    CF 548A
    【冰茶几专题】F
    【冰茶几专题】C
    535 C.Tavas and karafs
    [WA]cf 534 D. Handshakes
    cf 534C. Polycarpus' Dice
  • 原文地址:https://www.cnblogs.com/CHINATYY/p/14802564.html
Copyright © 2011-2022 走看看