图论——三种存图方式

  今年暑假入坑了ACM,可以说开始的很晚了。平时看到各位大佬们的博客都写的很是精彩了,也想通过写博客来督促一下自己,总结一下自己的每天所学和一些感受吧,希望能一直坚持下去,这条路注定不会好走,那就坦然去接受一场场爆零,从零开始慢慢积累吧。(刚开始入坑,写的内容可能会有很多很多的问题,希望大家多多指出,一起进步。)

  本来是最近在准备学习网络流,但是发现,基础差到模板里建图就有些不会,于是先来学学习如果存图,大概有三种这样的方式:

一、邻接矩阵存图

   顾名思义就是用矩阵来记录一个图,矩阵中第 i 行第 j 列的值就表示顶点 i 到顶点 j 的权值。

  

#include<bits/stdc++.h>
const int V = 1000;  //最大顶点数
int mat[maxn][maxn];//开设二维数组来存矩阵

int main()
{
    int i,j,w;
    memset(mat, 0, sizeof(mat));  //初始化操作假设权值为0表示没有该边
    scanf("%d%d%d",&i,&j,&w);//输入边的信息:起点、终点、权重

    mat[i][j] = w;// //增加顶点i到顶点j的权值为w的边
    mat[i][j] = 0;//删除边
    printf("%d",mat[i][j]);//查询边
}

  优点:容易理解,如果矩阵已经确定,可在O(1)的时间复杂度实现添加,修改,删除的操作

缺点:空间复杂度过高,并且极为致命,一旦顶点数过多,需要利用空间就很大,而当图很稀疏时候,就会造成内存的浪费

二、邻接表

   邻接表存储,又叫链式存储。这里主要说一下用数组的方式来模拟建立邻接表,特别是在网络流应用中,要建立好多好多数组,分别存取边的起点、终点、特别是还要存权重的数组域。具体解释看代码:

#include<bits/stdc++.h>
#define maxn 1000001
#define INF 119260817
using namespace std;
int  cnt,cost[maxn],from[maxn],to[maxn],Next[maxn], head[maxn];
int n,m;
void add(int x,int y,int z)//建边
{
    ++cnt;
    cost[cnt]=z;//权重
    from[cnt]=x;起点
    to[cnt]=y;//汇点
    Next[cnt]=head[x];//存边表,存储上个边的号head[x],形成链表
    head[x]=cnt;//记录每个起点的相连的一个点,就是所在链表的起点
}
int main()
{
    cnt=1;
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);//输入n个顶点,m条边
    for(int i=1;i<=m;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);//起点、终点、权重
        add(x,y,z);add(y,x,0);      //刚开始要建反向边,容量是0
    }
}

  由代码可知:此方法时间、空间复杂度都是O(m),遍历一条链表时复杂度也为O(m),远小于邻接矩阵中的O(n2)。

三、链式向前星

感觉和邻接表存储有点相似,通过结构体数组来存储边的终点、上一个边、权重(因为一个结点同一起点所以不需要存起点了),再加一个head数组,head数组来存边的序号。

 

const int maxn = 10005;   //点的最大个数
int head[maxn], cnt=0;//head数组用来表示以i为起点的一条边存储的位置
                                  //cnt用来记录序号

struct Edge
{
    int to; //此边的终点
    int w; //此边的权重
    int next; //同一起点的上一条边的储存位置
}Edge edge[maxn];

void add(int u,int v,int w)  //初始化加边
{
    edge[cnt].w = w;//记录边的权重
    edge[cnt].to = v;//记录边的终点
    edge[cnt].next = head[u];//存储同一起点的上一条边的位置
    head[u] = cnt++;//给边赋予序号
}

int main()  //遍历所有链表
{
    for(int i=0; i<=n; i++)
        for(int j=head[i]; j!=-1; j=edge[j].next)
             {......}//具体操作省略
}

与上面邻接矩阵相比,最大缺点就是,一开始不容易理解了,需要先看下数据结构链表的东西,这个方法很节省内存,效率高。

这就是三种存图的方式,学会了这三种就可以进一步学习图论的一些算法了。

要一直坚持下去哦!

原文地址:https://www.cnblogs.com/dreamxy/p/11251628.html

时间: 2024-11-02 02:38:52

图论——三种存图方式的相关文章

Count on a tree SPOJ 主席树+LCA(树链剖分实现)(两种存图方式)

Count on a tree SPOJ 主席树+LCA(树链剖分实现)(两种存图方式) 题外话,这是我第40篇随笔,纪念一下.<( ̄︶ ̄)[GO!] 题意 是说有棵树,每个节点上都有一个值,然后让你求从一个节点到另一个节点的最短路上第k小的值是多少. 解题思路 看到这个题一想以为是树链剖分+主席树,后来写着写着发现不对,因为树链剖分我们分成了一小段一小段,这些小段不能合并起来求第k小,所以这个想法不对.奈何不会做,查了查题解,需要用LCA(最近公共祖先),然后根据主席树具有区间加减的性质,我们

LVS:三种负载均衡方式比较+另三种负载均衡方式

转:http://blog.csdn.net/u013256816/article/details/50705578 什么是LVS? ??首先简单介绍一下LVS (Linux Virtual Server)到底是什么东西,其实它是一种集群(Cluster)技术,采用IP负载均衡技术和基于内容请求分发技术.调度器具有很好的吞吐率,将请求均衡地转移到不同的服务器上执行,且调度器自动屏蔽掉服务器的故障,从而将一组服务器构成一个高性能的.高可用的虚拟服务器.整个服务器集群的结构对客户是透明的,而且无需修

LVS:三种负载均衡方式比较

转载于http://soft.chinabyte.com/25/13169025.shtml 1.什么是LVS? 首先简单介绍一下LVS (Linux Virtual Server)到底是什么东西,其实它是一种集群(Cluster)技术,采用IP负载均衡技术和基于内容请求分发技术.调度器具有很好的吞吐率,将请求均衡地转移到不同的服务器上执行,且调度器自动屏蔽掉服务器的故障,从而将一组服务器构成一个高性能的.高可用的虚拟服务器.整个服务器集群的结构对客户是透明的,而且无需修改客户端和服务器端的程序

RHEL7、CentOS7提供三种命令行方式方式来设置和显示日期

RHEL7.CentOS7提供三种命令行方式方式来设置和显示日期.时间.timedatectl是在RHEL7及CentOS7中新增的systemd的一部分,date是传统的日期时间设置命令,hwclock单元访问的是硬件时钟. 一.timedatectl [root@Geeklp-Administrator ~]# timedatectl Local time: 六 2017-12-16 19:49:53 CST Universal time: 六 2017-12-16 11:49:53 UTC

三种加载方式

重点总结:    即:三种加载方式    1>传统加载方式------默认路径:tomcat/bin/目录    2>使用ServletContext对象-----默认路径:web应用(工程)目录    3>使用类加载器------默认路径:WEB-INF/classes/目录 一.利用ServletContext对象读取资源文件--默认目录为:工程(应用)路径                重点方法:                        InputStream getReso

.NET中的三种接口实现方式

摘自:http://www.cnblogs.com/zhangronghua/archive/2009/11/25/1610713.html 一般来说.NET提供了三种不同的接口实现方式,分别为隐式接口实现.显式接口实现.混合式接口实现.这三种方式各有各的特点. 首先来看隐式接口实现,这恐怕是我们使用最多的一种接口实现,因为隐匿接口实现是.NET的默认接口实现方式.下面让我们来看一个隐式接口实现的例子: using System; internal class MyClass { public

Apache Spark探秘:三种分布式部署方式比较

目前Apache Spark支持三种分布式部署方式,分别是standalone.spark on mesos和 spark on YARN,其中,第一种类似于MapReduce 1.0所采用的模式,内部实现了容错性和资源管理,后两种则是未来发展的趋势,部分容错性和资源管理交由统一的资源管理系统完成:让Spark运行在一个通用的资源管理系统之上,这样可以与其他计算框架,比如MapReduce,公用一个集群资源,最大的好处是降低运维成本和提高资源利用率(资源按需分配).本文将介绍这三种部署方式,并比

Binding 中 Elementname,Source,RelativeSource 三种绑定的方式

在WPF应用的开发过程中Binding是一个非常重要的部分. 在实际开发过程中Binding的不同种写法达到的效果相同但事实是存在很大区别的. 这里将实际中碰到过的问题做下汇总记录和理解. 1. source = {binding} 和source = {binding RelativeSource={RelativeSource self},Path=DataContext}效果相同 理解:{binding} 不设定明确的绑定的source,这样binding就去从本控件类为开始根据可视树的层

PDO的三种连接数据库的方式

PDO的三种连接数据库的方式 PDO的出现是为了解决PHP与各个数据库的连接处理都有各自的函数的问题,它的高度抽象,使得使用起来极其的方便.由于最常用的搭配就是PHP+Mysql,所以这里就以连接mysql为例. 一.参数形式 [php] view plaincopyprint? try{ $dsn      = 'mysql:host=localhost;dbname=myblog'; $username = 'root'; $passwd   = '123456'; $pdo      =