最近开始重新学习图论,就先从邻接矩阵与邻接表的存图开始吧。
给出一道模板题,模拟一下存图与调用的情景:
输入:
第一行输入两个整数n,m,表示在有m个点的有向图中有n条边。接下来共n行,每行三个整数x,y,z,表示从点x到点y有一条权值为z的边。
输出:
(不需顺序)输出n行,每行三个整数,表示一条边的起点,终点,权值。
邻接矩阵:
邻接矩阵是一个很简单便捷的存图方法。定义一个二维数组map[m+1][m+1],map[i][j]=w表示从点i到点j存在一条权值为w的路径。
然后用双重循环遍历map,如果大于0的就输出。
比较简单,代码就不打了,以后会打上。
邻接表:
不同于邻接矩阵的存图方法,想一想,如果在邻接矩阵中的map开到了很大,但这中间只有两条边,那么就浪费了很大空间。所以就有了邻接表。邻接表只存每条边,十分节省空间,但代码和思路麻烦一些。
邻接表其实是一个链表....
我们定义一个结构体:
struct edge{
int lo,w,v;
}a[n+1];
再来一个int数组last[m+1]
a[i].w表示第i条边(按输入顺序)的权值;a[i].v表示第i条边的终点;lo是last one的简称,a[i].lo表示上一条存过的跟第i条边同起点的边在结构体中的位置。
last[i]表示以点i为起点的边中最后存进去的一条边在结构体中的位置
直接上代码吧(含注释)
#include<stdio.h>
struct edge{
int lo,w,v;
}a[110];
int last[110],tot=0;
void add(int x,int y,int z)
{
a[++tot].v=y;//权值
a[tot].lo=last[x];//指向上一条以x为起点的边的位置
last[x]=tot;//更新以x为起点的最后一条边的位置
a[tot].w=z;//终点
}
void visit(int x)
{
for(int i=last[x];i>=1;i=a[i].lo)//从最后一个以x为起点的边位置开始往前访问,相当于链表
{
printf("%d %d %d\n",x,a[i].v,a[i].lo);
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)//初始化,使每次第一次存以i为起点的边时,指向-1
last[i]=-1;
for(int i=1;i<=n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);//存入
}
for(int i=1;i<=m;i++)
visit(i);//访问并输出
return 0;
}