链式前向星
题目:
给你一个有 n 个点和 m 条边(允许有重边)的无向图及每条边的边权,求:和点 k 所有相连的边的终点和边权,以及相连的边数。(此题也可暴力枚举,但为了讲前向星,还是用了前向星来做)
输入输出格式:
输入格式:
输入数据第一行两个数 n,m,意义如题目所示。
接下来 m 行每行有 3 个用空格隔开的数,其中第 i 行的 3 个数 x[i],y[i],w[i] 分别表示第 i 条边的起点、终点和边权。
最后一行仅一个数 k,表示要查询的点,查询内容如题所示。
输出格式:
共 t+1 行。
前 t 行每行两个数,其中第 j 行的两个数分别代表第 j 条与 k 相连的边的终点和边权,之间用空格隔开。
最后一行一个整数 s,表示与 k 点相连的边数。
注意:输出的前 t 行的边的顺序可以打乱,即第 j 条边放在某一条边的前面或后面输出是同样的答案,但禁止重复输出(除非两条相同的边)!!!
样例输入:
4 5 1 4 3 3 2 2 1 2 1 4 3 4 1 4 2 4
样例输出:
1 2 3 4 1 3 3
介绍:前向星用一维数组实现,是邻接矩阵(二维数组实现)的优化,大大节省了存储空间和查找时间,在图论和需建图解题的题目中发挥着极大的作用!!!(当然此题也可以用邻接矩阵做,但数据一旦超过 3000 ,甚至达到 一万 或 十万 甚至 百万千万 的话,邻接矩阵就完全无能为力了)
了解之后,让我们来真正接触一下前向星吧!
First:构建链式前向星~(也是核心步骤)
1 procedure add(x,y,z:longint); //加一条从 x 到 y 的边权为 w 的边 2 begin 3 inc(tot); //此条边的编号 4 next[tot]:=first[x]; // next 记录下一条边的编号(边的顺序 5 无所谓) 6 first[x]:=tot; // first 记录第一条边的编号(哪条边作 7 为第一条边也无所谓) 8 en[tot]:=y; // en 记录编号为 tot 的边的终点 9 len[tot]:=z; // len 记录编号为 tot 的边的边权 10 end;
1 for i:=1 to m do 2 begin 3 readln(x,y,w); 4 add(x,y,w); //调用函数建表(正向建一次) 5 add(y,x,w); //调用函数建表(反向建一次) 6 end; 7 (因为是无向边,所以要正反建两次~)
Next:线性查询!!!
now:=first[k]; //找起点为 k 的第一条边的编号 while now<>0 do //当边的编号不为零即还有边未询问是进 行线性查询 begin writeln(en[now],' ',len[now]);//找到一条边,就输出信息,因为可以乱 序(若按字典序输出,则存进数组里排 一下序就好啦~) now:=next[now]; //线性查询下一条边(查询操作中的精 髓!) inc(cnt); //累计边的个数 end;
Last:输出~
其实你们应该早发现了,在线性查询的过程中以经输出过终点和边权了,且剩下要输出的边数 s 其实就是 t 即程序中的 cnt !!!(废话!这只要是个人都能看出来的好吗?!)
于是 writeln(cnt); 就完美地结束了此题!!!
以下是标程!!!
1 var 2 x,y,w,tot,i,n,k,now,e,m,cnt:longint; 3 first,en,next,len:array[0..1000001] of longint; 4 procedure add(x,y,w:longint); //建表函数 5 begin 6 inc(tot); 7 next[tot]:=first[x]; 8 first[x]:=tot; 9 en[tot]:=y; 10 len[tot]:=w; 11 end; 12 begin 13 readln(n,m); 14 for i:=1 to m do //调用函数建表 15 begin 16 readln(x,y,w); 17 add(x,y,w); 18 add(y,x,w); 19 end; 20 readln(k); 21 now:=first[k]; //开始查询 22 while now<>0 do 23 begin 24 writeln(en[now],' ',len[now]); //边询问边输出 25 now:=next[now]; 26 inc(cnt); 27 end; 28 writeln(cnt); //最后输出边数此题完美结束 29 end.
学后推荐一个用到前向星的模板:最小生成树 Prim 算法