2023年7月30日发(作者:)
图的邻接表存储方式——数组实现初探
焦作市外国语中学 岳卫华
在图论中,图的存储结构最常用的就是就是邻接表和邻接矩阵。一旦顶点的个数超过5000,邻接矩阵就会“爆掉”空间,那么就只能用邻接表来存储。比如noip09的第三题,如果想过掉全部数据,就必须用邻接表来存储。
但是,在平时的教学中,发现用动态的链表来实现邻接表实现时,跟踪调试很困难,一些学生于是就觉得邻接表的存储方式很困难。经过查找资料,发现,其实完全可以用静态的数组来实现邻接表。本文就是对这种方式进行探讨。
我们知道,邻接表是用一个一维数组来存储顶点,并由顶点来扩展和其相邻的边。具体表示如下图:
其相应的类型定义如下:
type
point=^node;
node=record
v:integer; //另一个顶点
next:point; //下一条边
end;
var
a:axv]of point;
而用数组实现邻接表,则需要定义两个数组:一个是顶点数组,一个是边集数组。 顶点编号
此边的另一邻接点
结点相临边的总数s
边权值
第一条邻接边next
下一个邻接边
对于上图来说,具体的邻接表就是:
由上图我们可以知道,和编号为1的顶点相邻的有3条边,第一条边在边集数组里的编号是5,而和编号为5同一个顶点的下条边的编号为3,再往下的边的编号是1,那么和顶点1相邻的3条边的编号分别就是5,3,1。同理和顶点3相邻的3条边的编号分别是11,8,4。
如果理解数组表示邻接表的原理,那么实现就很容易了。
类型定义如下:
type
node=record //点集数组
s,next:longint; //s为 与第i个点相临的边有多少个,next为多少?
end;
为第一条边的编号
edge=record //边集数组
y,v,next:longint; // y为这条边的另一个顶点,v为权值,next为和第i个节点相临的另一条边,next为0 则表示结束。
end;
var
a:axn] of node;
e:axm] of edge;
见图的代码和动态邻接表类似:
readln(x1,y1,v1);
inc(m); e[m].y:=y1;e[m].v:=v1; e[m].next:=a[x1].next;
a[x1].next:=m;
inc(a[x1].s);
inc(m); e[m].y:=x1;e[m].v:=v1; e[m].next:=a[y1].next;
a[y1].next:=m;
inc(a[y1].s);
下面提供一道例题
邀请卡分发/c/cpp
【题目描述】 AMS公司决定在元旦之夜举办一个盛大展览会,将广泛邀请各方人士参加。现在公司决定在该城市中的每个汽车站派一名员工向过往的行人分发邀请卡。
但是,该城市的交通系统非常特别,每条公共汽车线路都是单向的,且只包含两个车站,即起点站与终点站,汽车从起点到终点站后空车返回。
假设AMS公司位于1号车站,每天早上,这些员工从公司出发,分别到达各自的岗位进行邀请卡的分发,晚上再回到公司。
请你帮AMS公司编一个程序,计算出每天要为这些分发邀请卡的员工付的交通费最少为多少?
【输入文件】
输入文件的第一行包含两个整数P和Q
(1<=P<=10000,0<=Q<=20000)。P为车站总数(包含AMS公司),Q为公共汽车线路数目。接下来有Q行,每行表示一条线路,包含三个数:起点,终点和车费。所有线路上的车费是正整数,且总和不超过1000000000。并假设任何两个车站之间都可到达。
【输出文件】
输出文件仅有一行为公司花在分发邀请卡员工交通上的最少费用。
【样例输入】
Case1:
2 2 1 2 13
2 1 33
Case2:
4 6
1 2 10
2 1 60
1 3 20
3 4 10
2 4 5
4 1 50
【样例输出】
Case1:
46
Case2:
210
【分析】此题是一道基本最短路径问题,但是如果想通过全部数据,10000个点,20000条边,必须用邻接表来实现。
下面给出此题目用dijkstra和 spfa两种算法的实现。 program delive_dijstrkalr;
const
inf='';
ouf='';
maxm=20000;
maxn=10000;
type
node=record
s,next:longint; //s为 与第i个点相临的边有多少个,next为第一条边的编号为多少?
end;
edge=record
y,v,next:longint; // y为这条边的另一个顶点,v为权值,next为和第i个节点相临的另一条边,next为0 则表示结束。
end;
var
i,j,k,m,n,x1,y1,w1,ans:longint;
a,a1:axn] of node;
e,e1:axm] of edge;
d,d1:axn] of longint;
procedure dij; var
i,j,k,min,jj,kk:longint;
f:axn] of boolean;
begin
fillchar(d,sizeof(d),$7f);
fillchar(f,sizeof(f),false);
j:=a[1].next;
for i:=1 to a[1].s do
begin
k:=e[j].y;
d[k]:=e[j].v;
j:=e[j].next;
end;
//用邻接表 来 找 和 第1个点 相临的 点 ,并给 d数组赋初值。。。。
f[1]:=true; d[1]:=0;
for i:=2 to n do
begin
min:=maxlongint; k:=0;
for j:=1 to n do
if (not f[j]) and (d[j] begin min:=d[j]; k:=j; end; if k=0 then exit; f[k]:=true; jj:=a[k].next; for j:=1 to a[k].s do begin kk:=e[jj].y; if (not f[kk]) and ( d[k]+e[jj].v d[kk]:=d[k]+e[jj].v; jj:=e[jj].next; end; //邻接表的使用,要好好注意。。。 end; end; begin assign(input,inf);reset(input); assign(output,ouf);rewrite(output); fillchar(a,sizeof(a),0); fillchar(e,sizeof(e),0); fillchar(a1,sizeof(a1),0); fillchar(e1,sizeof(e1),0); readln(n,m); for i:=1 to m do begin readln(x1,y1,w1); e[i].y:=y1; e[i].v:=w1; e[i].next:=a[x1].next; a[x1].next:=i; inc(a[x1].s); e1[i].y:=x1; e1[i].v:=w1; e1[i].next:=a1[y1].next; a1[y1].next:=i; inc(a1[y1].s); end; dij; d1:=d; a:=a1; e:=e1; dij; ans:=0; for i:=2 to n do ans:=ans+d[i]+d1[i]; writeln(ans); close(input);close(output); end. program deliver; const inf=''; ouf=''; maxm=20000; maxn=10000; type node=record s,next:longint; //s为 与第i个点相临的边有多少个,next为第一条边的编号为多少? end; edge=record y,v,next:longint; // y为这条边的另一个顶点,v为权值,next为和第i个节点相临的另一条边,next为0 则表示结束。 end; var i,j,k,m,n,x1,y1,w1,ans:longint; a,a1:axn] of node; e,e1:axm] of edge; d,d1:axn] of longint; q:array[1..100000] of longint; procedure spfa; //spfa 是基于边的松弛操作的最短路径求法。基本原理就是 var i,j,k,now,min,t,w:longint; f:axn] of boolean; begin fillchar(d,sizeof(d),$7f); fillchar(f,sizeof(f),false); fillchar(q,sizeof(q),0); d[1]:=0; t:=1;f[1]:=true; w:=1; q[t]:=1; repeat k:=q[t]; j:=a[k].next; for i:=1 to a[k].s do begin now:=e[j].y; if d[now]>d[k]+e[j].v then begin d[now]:=d[k]+e[j].v; if not f[now] then begin inc(w); q[w]:=now; f[now]:=true; end; end; j:=e[j].next; end; f[k]:=false; inc(t); until t>w; end; begin assign(input,inf);reset(input); assign(output,ouf);rewrite(output); fillchar(a,sizeof(a),0); fillchar(e,sizeof(e),0); fillchar(a1,sizeof(a1),0); fillchar(e1,sizeof(e1),0); readln(n,m); for i:=1 to m do begin readln(x1,y1,w1); e[i].y:=y1; e[i].v:=w1; e[i].next:=a[x1].next; a[x1].next:=i; inc(a[x1].s); e1[i].y:=x1; e1[i].v:=w1; e1[i].next:=a1[y1].next; a1[y1].next:=i; inc(a1[y1].s); end; spfa; d1:=d; a:=a1; e:=e1; spfa; ans:=0; for i:=2 to n do ans:=ans+d[i]+d1[i]; writeln(ans); close(input);close(output); end.
发布者:admin,转转请注明出处:http://www.yc00.com/web/1690723235a408072.html
评论列表(0条)