图的存储——邻接表

11 篇文章 0 订阅

说明

在许多图论的题中,存储图是必不可少的,这里就来说说我平时存储图的方式,与大家交流交流 罒V罒

容器

#说明
num记录到现在已经存了多少条边了(在添加边的时候会用到)
head[x]以 x 为入点的某一条边的编号
.to第 x 条边的下一条边的编号(可以把它想象为一个通往下一个边的链接)
.v这一条边的出点(入点当然还是开始的那个head[x]中的x)
.w边权值(不需要的话可以不要,根据题目也可以再加几个参数)
int head[N],num;
struct edge{
    int to,v,w;
} e[N];

添加边

  • 看看程序和注释,感受一下吧
void add(int u,int v,int w){
    num++;              //新的一条边 
    e[num].v=v;         //处理一下这条边的信息 
    e[num].w=w;
    e[num].to=head[u];  //把 当前 head[u] 那条边接到 num 后面 
    head[u]=num;        //把这条边接到 u 的 head[] 上 
}

枚举边

  • 当我们我们需要枚举所有以某个点(这里就当成是 x 吧)为入点的边,就可以用到下面的程序
  • 由于起初 e[].to 都是 0 (当然我是这样的,你们喜欢也可以初始化成-1),所以就用 e[].to 是否为0来判断判断是否还有边。
  • 这个代码是为了理解才这么长,最后提示中有个不错的宏定义,平时就用那个,又快又方便!
for (int i=head[x],o; i!=0; i=e[i].to){
    o=e[i].v;
    //这里就可以做各种处理操作
    printf("%d -> %d (%d)\n",x,o,e[i].w);
}

遍历图

  • 要是是个图,那么就用个数组 f[] 来记录某个点是否已经讨论过了(有时按题目需要,可能是用时间戳,不过也差不多……)
  • 代码被我简化了,For(x) 意思就是上面那个枚举边, o 就是枚举出的出点。
void dfs(int x){
    f[o]=1;
    For(x) if (!f[o]){
        //这里可以做各种操作 
        dfs(o);
    }
}
  • 要是目标是个树(特殊的图,没有环出现),那么我们就可以省掉 f[] 的空间,每次传个当前节点的父节点 fa 就行了。
  • 原理大概就是……可以自己画个图,感受一下
void dfs(int x,int fa) {
    For(x) if (o!=fa){
        //这里可以做各种操作
        dfs(o,x) ;
    }
}

提示

  • 有的比赛(比如 codeforces)中,不仅要求你做出题目,完成的速度也是评分的一个要素,那么你就需要好好利用宏定义来简化代码,这样对别人看懂你的代码这方面也有很大帮助。
  • 比如你就可以定义一个 For,让程序更简洁
#define For(x) for (int h=head[x],o=e[h].v; h; o=e[h=e[h].to].v)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值