今天讲图最基本的东西---储存;
一、邻接矩阵:a[i,j]:=...(指从点i到点j的距离);存储方便,但损耗空间太多,若有10000个点就不行了。
二、邻接表:
这里需要使用指针:
这需要逆向保存,代码如下:
1 type 2 point=^node; 3 node=record 4 u,v:longint; //u是和该点有边连接的点,v指这条边的权值。 5 next:point; 6 end; 7 var 8 n,m,x,y,j:longint; //n是点的数量,m是边的数量 9 a:array[1..maxn]of point; 10 p:point;//如果要调用的话,需要加上head指针,否则直接用,就回不到最初的地址 11 begin 12 readln(n,m); 13 for i:=1 to m do 14 begin 15 readln(x,y,j); 16 new(p); p^.u:=y; p^.v:=a[x]; a[x]:=p; 17 new(p); p^.u:=x; p^.v:=a[y]; a[y]:=p; 18 end; 19 end. 20 //这样建的邻接表就和上图一样,大家可以手动尝试一下。
三、一个特殊且非常漂亮的结构,并查集:
并查集可以管理元素分组,①.查询元素a、b是否在同一组;②.合并元素a、b所在的组
并查集可用数来储存(不是二叉树),优化时,可以将根节点以下的点全部指向根结点,使高度从n变为2,复杂度大大大降低。
如果不清楚,可以先上网搜,再看下面的程序,手动画一下(画成树):
1 var 2 fa:array[1..maxn]of longint //记录点i的父亲,不是祖先 3 {high:array[1..maxn]of longint //树的高度} 4 function find(k:longint):longint; //查询元素k的祖先 5 begin 6 if fa[x]=x then exit(x) 7 else fa[x]=find(fa[x]); //非常重要,将所有的点全部指向根节点(祖先),降低复杂度 8 exit(fa[x]); 9 end; 10 procedure unite(x,y:longint);//合并元素x,y所在的集合 11 var 12 a,b:longint; 13 begin 14 a:=find(x); 15 b:=find(y); 16 if a<>b then fa[a]:=b; 17 {if high[a]<high[b] then fa[a]:=b 18 else begin fa[b]:=a;if high[a]=high[b] then inc(rank[a]); end; } 19 end; 20 //有{}的代码可要可不要,对做题影响不大 21 初始化时,fa[i]:=i;high[i]:=0;
代码很短(去掉我加的注释),非常非常好用且漂亮的结构。