数据结构(Java语言实现) 课件 第6章 图_第1页
数据结构(Java语言实现) 课件 第6章 图_第2页
数据结构(Java语言实现) 课件 第6章 图_第3页
数据结构(Java语言实现) 课件 第6章 图_第4页
数据结构(Java语言实现) 课件 第6章 图_第5页
已阅读5页,还剩55页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第6章图结构Java实据现数目录CONTENTS6.1

图的定义及相关概念6.2图的存储结构6.3图的遍历6.6最短路径6.4图的连通性问题6.5有向无环图6.7小结6.1图的定义及相关概念6.1.1图的定义图由数据元素集合与边的集合构成。数据元素常称为顶点(Vertex),顶点集合(V)不能为空,边(E)表示顶点之间的关系,用连线表示。图(G)的形式化定义为:G=(V,E),其中,V={x|x∈数据元素集合},E={<x,y>|Path(x,y)/\(x∈V,y∈V)}。Path(x,y)表示从x与y的关系属性。如果<x,y>∈E,则<x,y>表示从顶点x到顶点y的一条弧(Arc),x称为弧尾(Tail)或起始点(Initialnode),y称为弧头(Head)或终端点(Terminalnode)。6.1图的定义及相关概念6.1.1图的定义如果<x,y>∈E且有<y,x>∈E,则用无序对(x,y)代替有序对<x,y>和<y,x>,表示x与y之间存在一条边(Edge),将这样的图称为无向图。6.1图的定义及相关概念6.1.1图的定义对于无向图,边数e的取值范围为0~n(n-1)/2。将具有n(n-1)/2条边的无向图称为完全图。对于有向图,弧度e的取值范围是0~n(n-1)。将具有n(n-1)条弧的有向图称为有向完全图。具有e<nlogn条弧或边的图,称为稀疏图(Sparsegraph)。具有e>nlogn条弧或边的图,称为稠密图(Densegraph)。6.1图的定义及相关概念6.1.2图的相关概念1.邻接点在无向图G=(V,E)中,如果存在边(vi,vj)∈E,则称vi和vj互为邻接点(Adjacent),即vi和vj相互邻接。边(vi,vj)依附于顶点vi和vj,或者称边(vi,vj)与顶点vi和vj相互关联。2.顶点的度在无向图中,顶点v的度是指与v相关联的边的数目,记作TD(v)。在有向图中,以顶点v为弧头的数目称为顶点v的入度(InDegree),记作ID(v)。以顶点v为弧尾的数目称为v的出度(OutDegree),记作OD(v)。顶点v的度为以v为顶点的入度和出度之和,即TD(v)=ID(v)+OD(v)。6.1图的定义及相关概念6.1.2图的相关概念3.路径在图中,从顶点vi出发经过一系列的顶点序列到达顶点vj称为从顶点vi到vj的路径(Path)。路径的长度是路径上弧或边的数目。4.子图假设存在两个图G={V,E}和G’={V’,E’},如果G’的顶点和关系都是V的子集,即有V’V,E’E,则G’为G的子图。6.1图的定义及相关概念6.1.2图的相关概念5.连通图和强连通图在无向图中,如果从顶点vi到顶点vj存在路径,则称顶点vi到vj是连通的。推广到图的所有顶点,如果图中的任何两个顶点之间都是连通的,则称图是连通图(ConnectedGraph)。无向图中的极大连通子图称为连通分量(ConnectedComponent)。6.1图的定义及相关概念6.1.2图的相关概念6.生成树一个连通图(假设有n个顶点)的生成树是一个极小连通子图,它含有图中的全部顶点,但只有足以构成一棵树的n-1条边。6.1图的定义及相关概念6.1.2图的相关概念7.网在实际应用中,图的边或弧往往与具有一定意义的数有关,即每一条边都有与它相关的数,称为权,这些权可以表示从一个顶点到另一个顶点的距离或花费等信息。这种带权的图称为带权图或网。一个网如图6.6所示。6.1图的定义及相关概念6.1.3图的抽象数据类型7.网在实际应用中,图的边或弧往往与具有一定意义的数有关,即每一条边都有与它相关的数,称为权,这些权可以表示从一个顶点到另一个顶点的距离或花费等信息。这种带权的图称为带权图或网。一个网如图6.6所示。ADTGraph{

数据对象V:V是具有相同特性的数据元素的集合,称为顶点集。数据关系R:R={VR}VR={<x,y>|x,y∈V且P(x,y>,<x,y>表示从x到y的弧,谓词P(x,y>定义了弧<x,y>的意义或信息}6.1图的定义及相关概念6.1.3图的抽象数据类型基本操作:

(1)CreateGraph(&G)

初始条件:图G不存在。

操作结果:创建一个图G。

(2)DestroyGraph(&T)

初始条件:图G存在。

操作结果:销毁图G。

(3)LocateVertex(G,v)

初始条件:图G存在,顶点v合法。

操作结果:若图G存在顶点v,则返回顶点v在图G中的位置。若图G中没有顶点v,则函数返回值为空。

(4)GetVertex(G,i)

初始条件:图G存在。

操作结果:返回图G中序号i对应的值。i是图G某个顶点的序号,返回图G中序号i对应的值。6.1图的定义及相关概念6.1.3图的抽象数据类型(5)FirstAdjVertex(G,v)

初始条件:图G存在,顶点v的值合法。操作结果:返回图G中v的第一个邻接顶点。若v无邻接顶点或图G中无顶点v,则函数返回-1。(6)NextAdjVertex(G,v,w)

初始条件:图G存在,w是图G中顶点v的某个邻接顶点。操作结果:返回顶点v的下一个邻接顶点。若w是v的最后一个邻接顶点,则函数返回-1。(11)DFSTraverseGraph(G)

初始条件:图G存在。操作结果:从图中的某个顶点出发,对图进行深度遍历。(12)BFSTraverseGraph(G)

初始条件:图G存在。操作结果:从图中的某个顶点出发,对图进行广度遍历。}ADTGraph6.2图的存储结构6.2.1邻接矩阵表示法图的邻接矩阵表示(AdjacencyMatrix)也称为数组表示。它采用两个数组来表示图:一个是用于存储顶点信息的一维数组,另一个是用于存储图中顶点之间的关联关系的二维数组,这个关联关系数组称为邻接矩阵。6.2图的存储结构学习基础学习认知能力两个图弧和边的集合分别为A={<A,B>,<A,C>,<A,D>,<C,A>,<C,B>,<D,A>}和E={(A,B),(A,D),(B,C),(B,D),(C,D)}。它们的邻接矩阵表示如图6.7所示。6.2图的存储结构学习基础学习认知能力enumKind{DG,DN,UG,UN}//图的类型publicclassMGraph{Stringvex[];

//用于存储顶点

doublearc[][];

//邻接矩阵,存储边或弧的信息

intvexnum,arcnum;//顶点数#边(弧)的数目

Kindkind;//图的类型

finalintMAXSIZE=20;}带权图的邻接矩阵表示如图6.8所示。MGraph(){vex=newString[MAXSIZE];arc=newdouble[MAXSIZE][MAXSIZE];arcnum=0;vexnum=0;kind=Kind.UG;}6.2图的存储结构学习基础学习认知能力表头结点有两个域组成:数据域和指针域。其中,数据域用来存放顶点信息,指针域用来指向边表中的第一个结点。通常情况下,表头结点采用顺序存储结构实现,边表结点由三个域组成:邻接点域、数据域和指针域。6.2.2邻接表表示法6.2图的存储结构学习基础学习认知能力6.2.2邻接表表示法图6.1所示的两个图G1和G2用邻接表表示如图6.11所示。图6.8所示的带权图用邻接表表示如图6.12所示。6.2图的存储结构图的邻接表存储结构描述如下:enumGKind{DG,DN,UG,UN}//图的类型classArcNode//边结点的类型定义{intadjvex;//弧指向的顶点的位置

ArcNodenextarc;//指示下一个与该顶点相邻接的顶点

Stringinfo;//与弧相关的信息

ArcNode(intadjvex){this.adjvex=adjvex;this.nextarc=null;}}classVNode//头结点的类型定义{Stringdata;ArcNodefirstarc;VNode(Stringdata){this.data=data;//用于存储顶点

this.firstarc=null;

//指向第一个与该顶点邻接的顶点

}}classAdjGraph//图的类型定义{finalintMAXSIZE=20;VNodevertex[];intvexnum,arcnum;//图的顶点数目、弧的数目

GKindkind;AdjGraph()

{vertex=newVNode[MAXSIZE];vexnum=0;arcnum=0;kind=GKind.UG;}6.2图的存储结构图6.1所示的有向图G1的逆邻接链表如图6.13所示。求某个顶点的入度,需要建立一个有向图的逆邻接链表,也就是为每个顶点vi建立一个以vi为弧头的链表。6.2图的存储结构【例6.2】编写算法,采用邻接表创建一个无向图G。for(k=0;k<arcnum;k++)//建立边链表

{Stringv[]=sc.nextLine().split("");inti=LocateVertex(v[0]);intj=LocateVertex(v[1]);//j为入边i为出边创建邻接表

ArcNodep=newArcNode(j);p.nextarc=vertex[i].firstarc;vertex[i].firstarc=p;//i为入边j为出边创建邻接表

p=newArcNode(i);p.nextarc=vertex[j].firstarc;vertex[j].firstarc=p;}6.2图的存储结构6.2.3十字链表十字链表是有向图的又一种链式存储结构。在十字链表中,将表头结点称为顶点结点,边结点称为弧结点。其中,顶点结点包含三个域:数据域和两个指针域。两个指针域,一个指向以顶点为弧头顶点,另一个指向以顶点为弧尾的顶点,数据域存放顶点的信息。6.2图的存储结构6.2.4邻接多重表邻接多重表(AdjacencyMulti_list)表示是无向图的另一种链式存储结构。顶点结点由两个域构成:data域和firstedge域。数据域data用于存储顶点的数据信息,firstedga域指示依附于顶点的第一条边。边结点包含六个域:mark域、ivex域、ilink域、jvex域、jlink域和info域。6.2图的遍历6.2.1图的深度优先遍历1.图的深度遍历的定义图的深度优先遍历是树的先根遍历的推广。图的深度优先遍历的思想是:从图中某个顶点v0出发,访问顶点v0的第一个邻接点,然后以该邻接点为新的顶点,访问该顶点的邻接点。重复执行以上操作,直到当前顶点没有邻接点为止。图的深度优先遍历的序列为:A、B、E、F、C、D、G、H、I。6.3图的遍历6.3.1图的深度优先搜索遍历publicvoidDFSTraverse(intvisited[])

//从第1个顶点起,深度优先遍历图

{

for(intv=0;v<vexnum;v++)

visited[v]=0;//访问标志数组初始化为未被访问

for(intv=0;v<vexnum;v++)

{

if(visited[v]==0)

DFS(v,visited);

//对未访问的顶点v进行深度优先遍历

}

System.out.println();

}

publicvoidDFS(intv,intvisited[])//从顶点v出发递归深度优先遍历图{visited[v]=1;//访问标志设置为已访问

System.out.print(vertex[v].data+"");//访问第v个顶点

intw=FirstAdjVertex(vertex[v].data);while(w>=0){if(visited[w]==0)DFS(w,visited);//递归调用DFS对v的尚未访问的序号为w的邻接顶点

w=NextAdjVertex(vertex[v].data,vertex[w].data);}}6.3图的遍历6.3.2图的广度优先遍历1.图的广度优先遍历的定义从图的某个顶点v出发,首先访问顶点v,然后按照次序访问顶点v的未被访问的每一个邻接点,接着访问这些邻接点的邻接点,并保证先被访问的邻接点的邻接点先访问,后被访问的邻接点的邻接点后访问的原则,依次访问邻接点的邻接点。例如,图G6的广度优先遍历的过程如图6.19所示。其中,箭头表示广度遍历的方向,图中的数字表示遍历的次序。6.3图的遍历图的广度优先搜索遍历

while(front<rear)//如果队列不空

{front=(front+1)%MaxSize;v=queue[front];//队头元素出队赋值给vArcNodep=vertex[v].firstarc;while(p!=null)//遍历序号为v的所有邻接点

{if(visited[p.adjvex]==0)//如果该顶点未被访问过

{visited[p.adjvex]=1;System.out.print(vertex[p.adjvex].data+"");rear=(rear+1)%MaxSize;queue[rear]=p.adjvex;}p=p.nextarc;//p指向下一个邻接点

}6.4图的连通性问题6.4.1无向图的连通分量与生成树图G3进行深度优先搜索遍历,得到的序列为:A、B、C、D、I、E和F、G、H。6.4图的连通性问题从某一个顶点出发,对图进行广度优先遍历,得到的生成树称为广度优先生成树。图6.21所示就是对应图G6的深度优先生成树和广度优先生成树。对于非连通图而言,从某一个顶点出发,对图进行深度优先遍历或者广度优先遍历,按照访问路径会得到一系列的生成树,这些生成树在一起构成生成森林。6.4图的连通性问题最小生成树就是指在一个连通网的所有生成树中,其中所有边的代价之和的那棵生成树。6.4.2最小生成树假设一个连通网N=(V,E),V是顶点的集合,E是边的集合,V有一个非空子集U。如果(u,v)是一条具有最小权值的边,其中,u∈U、v∈V-U,那么一定存在一个最小生成树包含边(u,v)。6.4图的连通性问题普里姆算法描述如下:假设N={V,E}是连通网,TE是N的最小生成树边的集合。执行以下操作:(1)初始时,令U={u0}(u0∈V)、TE=。(2)对于所有的边u∈U,v∈V-U的边(u,v)∈E,将一条代价最小的边(u0,v0)放到集合TE中,同时将顶点v0放进集合U中。(3)重复执行步骤(2),直到U=V为止。这时,边集合TE一定有n-1条边,T={V,TE}就是连通网N的最小生成树。1.普里姆算法6.4图的连通性问题例如,图6.23所示就是利用普里姆算法构造最小生成树的过程。6.4图的连通性问题需要设置一个数组closeedge[MaxSize],用来保存U到V-U最小代价的边。对于每个顶点v∈V-U,在数组中存在一个分量closeedge[v],它包括两个域adjvex和lowcost,其中,adjvex域用来表示该边中属于U中的顶点,lowcost域存储该边对应的权值。closeedge[v].lowcost=Min({cost(u,v)|u∈U})6.4图的连通性问题publicvoidPrim(MGraphM,Stringu,CloseEdgecloseedge[])

//利用Prim算法求从第u个顶点出发构造网G的最小生成树

{

intk=M.LocateVertex(u);//k为顶点u对应的序号

intm=0;

for(intj=0;j<M.vexnum;j++)//数组初始化

{

CloseEdgeclose_edge=newCloseEdge(u,M.arc[k][j]);

closeedge[m++]=close_edge;}

closeedge[k].lowcost=0;//初始时集合U只包括顶点u

System.out.println("最小代价生成树的各条边为:");

for(inti=1;i<M.vexnum;i++)//选择剩下的M.vexnum-1个顶点

{k=MiniNum(M,closeedge);//k为与U中顶点相邻接的下一个顶点的序号

System.out.print("("+closeedge[k].adjvex+"-"+M.vex[k]+")");//输出边

closeedge[k].lowcost=0;//第k顶点并入U集

for(intj=0;j<M.vexnum;j++){

if(M.arc[k][j]<closeedge[j].lowcost)//将最小边存入到列表

{

closeedge[j].adjvex=M.vex[k];

closeedge[j].lowcost=M.arc[k][j];}

}

}

}6.4图的连通性问题2.克鲁斯卡尔算法克鲁斯卡尔算法的基本思想是:假设N={V,E}是连通网,TE是N的最小生成树边的集合。执行以下操作:(1)初始时,最小生成树中只有n个顶点,这n个顶点分别属于不同的集合,而边的集合TE=。(2)从连通网N中选择一个代价最小的边,如果边所依附的两个顶点在不同的集合中,将该边加入到最小生成树TE中,并将该边依附的两个顶点合并到同一个集合中。(3)重复执行步骤(2),直到所有的顶点都属于同一个顶点集合为止。6.4图的连通性问题例如,图6.26所示就是利用卡鲁斯卡尔算法构造最小生成树的过程。6.5有向无环图1.AOV网在每一个工程过程中,可以将工程分为若干个子工程,这些子工程称为活动。如果用图中的顶点表示活动,以有向图的弧表示活动之间的优先关系,这样的有向图称为AOV网,即顶点表示活动的网。6.5.1AOV网与拓扑排序6.5有向无环图对AOV网进行拓扑排序的方法如下:(1)在AOV网中任意选择一个没有前驱的顶点即顶点入度为零,将该顶点输出。(2)从AOV网中删除该顶点,以及从该顶点出发的弧。(3)重复执行步骤(1)和(2),直到AOV网中所有顶点都已经被输出,或者AOV网中不存在无前驱的顶点为止。按照以上步骤,图6.26所示的AOV网的拓扑序列为:(C1,C2,C3,C4,C5,C6,C7,C8,C9,C10)或(C6,C7,C8,C9,C1,C2,C3,C4,C5,C10)拓扑排序6.5有向无环图图6.28所示是AOV网的拓扑序列的构造过程,其拓扑序列为:V1、V2、V3、V5、V4、V6。6.5有向无环图采用邻接表存储结构的AOV网的拓扑排序的算法实现:遍历邻接表,将各个顶点的入度保存在数组indegree中。将入度为零的顶点入栈,依次将栈顶元素出栈并输出该顶点,对该顶点的邻接顶点的入度减1,如果邻接顶点的入度为零,则入栈,否则,将下一个邻接顶点的入度减1并进行相同的处理。然后继续将栈中元素出栈,重复执行以上操作,直到栈空为止。拓扑排序while(!S.StackEmpty())//如果栈S不为空

{inti=S.PopStack();//从栈S将已拓扑排序的顶点i弹出

System.out.print(G.vertex[i].data+"");count+=1;//对入栈T的顶点计数

ArcNodep=G.vertex[i].firstarc;while(p!=null)//处理编号为i的顶点的每个邻接点

{intk=p.adjvex;//顶点序号为kindegree[k]-=1;if(indegree[k]==0)//如果k的入度减1后变为0,则将k入栈SS.PushStack(k);p=p.nextarc;}}6.5有向无环图.AOE网AOE网是一个带权的有向无环图。其中,用顶点表示事件,弧表示活动,权值表示两个活动持续的时间。AOE网是以边表示活动的网(ActivityOnEdgeNetwork)。图6.29所示是一个具有10个活动、8个事件的AOE网。v1、v2、…、v8表示8个事件,<v1,v2>、<v1,v3>、…、<v7,v8>表示10个活动,a1、a2、…、a10表示活动的执行时间。进入顶点的有向弧表示的活动已经完成,从顶点出发的有向弧表示的活动可以开始。顶点v1表示整个工程的开始,v8表示整个工程的结束。顶点v5表示活动a4、a5、a6已经完成,活动a7和a8可以开始。其中,完成活动a5和活动a6分别需要5天和6天。6.5.2AOE网与关键路径6.5有向无环图2.关键路径关键路径是指在AOE网中从源点到汇点路径最长的路径。这里的路径长度是指路径上各个活动持续时间之和。在AOE网中,有些活动是可以并行执行的。关键路径其实就是完成工程的最短时间所经过的路径,关键路径上的活动称为关键活动。(1)事件vi的最早发生时间:从源点到顶点vi的最长路径长度,称为事件vi的最早发生时间,记作ve(i)。求解ve(i)可以从源点ve(0)=0开始,按照拓扑排序规则根据递推得到:ve(i)=Max{ve(k)+dut(<k,i>)|<k,i>∈T,1≤i≤n-1}6.5有向无环图(2)事件vi的最晚发生时间:在保证整个工程完成的前提下,活动必须最迟的开始时间,记作vl(i)。在求解事件vi的最早发生时间ve(i)的前提vl(n-1)=ve(n-1)下,从汇点开始,向源点推进得到vl(i):vl(i)=Min{vl(k)-dut(<i,k>)|<i,k>∈S,0≤i≤n-2}(3)活动ai的最早开始时间e(i):如果弧<vk,vj>表示活动ai,当事件vk发生之后,活动ai才开始。因此,事件vk的最早发生时间也就是活动ai的最早开始时间,即e(i)=ve(k)。(4)活动ai的最晚开始时间l(i):在不推迟整个工程完成时间的基础上,活动ai最迟必须开始的时间。如果弧<vk,vj>表示活动ai,持续时间为dut(<k,j>),则活动ai的最晚开始时间l(i)=vl(j)-dut(<k,j>)。6.5有向无环图求AOE网的关键路径的算法如下:(1)对AOE网中的顶点进行拓扑排序,如果得到的拓扑序列顶点个数小于网中顶点数,则说明网中有环存在,不能求关键路径,终止算法;否则,从源点v0开始,求出各个顶点的最早发生时间ve(i)。(2)从汇点vn出发vl(n-1)=ve(n-1),按照逆拓扑序列求其他顶点的最晚发生时间vl(i)。(3)由各顶点的最早发生时间ve(i)和最晚发生时间vl(i),求出每个活动ai的最早开始时间e(i)和最晚开始时间l(i)。(4)找出所有满足条件e(i)=l(i)的活动ai,ai即是关键活动。6.5有向无环图利用求AOE网的关键路径的算法,图6.29所示的网中顶点对应事件最早发生时间ve、最晚发生时间vl以及及弧对应活动最早发生时间e、最晚发生时间如图6.30所示。网的关键路径是(v1,v2,v5,v6,v8),关键活动是a1、a4、a7和a9。6.6最短路径6.6.1从某个顶点到其余各顶点的最短路径1.从某个顶点到其他顶点的最短路径算法思想假设从有向图的顶点v0出发到其余各个顶点的最短路径。带权有向图G7及从v0出发到其他各个顶点的最短路径如图6.31所示。6.6最短路径从顶点v0到顶点v2有两条路径:(v0,v1,v2)和(v0,v2)。其中,前者的路径长度为70,后者的路径长度为60。因此,(v0,v2)是从顶点v0到顶点v2的最短路径。从顶点v0到顶点v3有三条路径:(v0,v1,v2,v3)、(v0,v2,v3)和(v0,v1,v3)。其中,第一条路径长度为120,第二条路径长度为110,第三条路径长度为130。因此,(v0,v2,v3)是从顶点v0到顶点v3的最短路径。6.6最短路径设有一个带权有向图D=(V,E),定义一个数组dist,数组中的每个元素dist[i]表示顶点v0到顶点vi的最短路径长度,则长度为dist[j]=Min{dist[i]|vi∈V}的路径,表示从顶点v0出发到顶点vj的最短路径。也就是说,在所有的顶点v0到顶点vj的路径中,dist[j]是最短的一条路径。而数组dist的初始状态是:如果从顶点v0到顶点vi存在弧,则dist[i]是弧<v0,vj>的权值,否则dist[j]的值为∞。6.6最短路径迪杰斯特拉算法求解最短路径步骤如下(用邻接矩阵存储):(1)初始时,S只包括源点v0,即S={v0},V-S包括除v0以外的图中的其他顶点。v0到其他顶点的路径初始化为dist[i]=G.arc[0][i].adj。(2)选择距离顶点vi最短的顶点vj,使得dist[j]=Min{dist[i]|vi∈V-S}dist[j]表示从v0到vj最短路径长度,vj表示对应的终点。(3)修改从v0到到顶点vi的最短路径长度,其中vi∈V-S。如果有dist[k]+G.arc[k][i]<dist[i],则修改dist[i],使得dist[i]=dist[k]+G.arc[k][i].adj。(4)重复执行步骤(2)和(3),直到所有从v0到其他顶点的最短路径长度求出。。6.6最短路径对图6.31所示的图G7求解从顶点v0到其他顶点的最短路径,求解过程如图6.32所示。6.6最短路径6.6.2每一对顶点之间的最短路径弗洛伊

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论