图论基础

图论基础

图的存储

在进行图的搜索之前,我们需要先了解图是通过怎样的方式存储下来的.
方式一:
邻接矩阵
开一个大小为O(|V|*|V|)的bool或int数组,用来存两个点之间是否有边以及边的其他信息(如边的数量以及边的权值等)

    int G[MAXN+5][MAXN+5];
    ......
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(满足某个条件)
                G[i][j]=G[j][i]=1;(有向图:G[i][j]=1)

优势:
这样可以用O(1)的之间来访问两点之间是否有边以及边上的信息,建图也十分方便,但是要注意的是,某些情况下需要进行特殊的初始化(如边权为0但是又有边时需要初始化为INF).有时也可采用多个邻接矩阵来存储各种信息.
局限:
内存占用巨大,遍历边的耗时过多,对于稀疏图的存储很亏.

方式二:
邻接表:
邻接表分两种存储方式.
vector邻接表:

    vector<int> G[MAXN+5];
    ......
    G[i].push_back(j);
//需要存边的信息时:
    struct edge
    {
        int v,val;
        //也可写一个重构函数
    };
    vector<edge> G[MAXN+5];
    ......
    G[i].push_back(edge(v,val));

手写邻接表:

    struct node
    {
        int v,/*边的其他信息*/;
        node *next,/**back*/;
    }
    node *Adj[MAXN+5],*ncnt=&edge[0];
    //如果有多组数据,切记要重新置为&edge[0]
    ......
    void AddEdge(int u,int v)
    {
        node *p=++ncnt;
        p->v=v;
        p->next=Adj[u];
        Adj[u]=p;
        /*反向边
        node *q=++ncnt;
        q->v=u;
        q->next=Adj[v];
        Adj[v]=q;
        p->back=q,q->back=p;
        */
    }
    ......
    //遍历:
    for(node *p=Adj[u];p!=NULL;p=p->next)
    {
        .....(对边的处理)
    }

也可以用在结构体里存vector,顺便存下各节点的信息的方法来构图;

优势:
节省内存(O(|V|+|E|)).
局限:
查找一条边是否存在是需要遍历,耗时巨大(但可以将邻接矩阵配合使用以节省时间).

图的遍历

以下均用手写邻接表的方式呈现
DFS

bool vis[MAXN+5];
void DFS(int u)
{
    vis[u]=true;
    for(node *p=Adj[u];p!=NULL;p=p->next)
    {
        int v=p->v;
        if(vis[v]==true)
            continue;
        DFS(v);
    }
    //vis[u]=false;如果需要的话,这叫"恢复现场"
}

例题:二染色问题,哈密顿路,计算连通块的数量
BFS

queue<int> q;
while(q.empty()==false)
{
    int u=q.front();
    q.pop();
    if(满足某个条件)
        break;
    for(node *p=Adj[u];p!=NULL;p=p->next)
    {
        int v=p->v;
        if(vis[v]==false)
        {
            vis[v]=true;
            q.push(v);
        }
    }
}

例题:
走迷宫(需要在)过程中用pre[]数组记录路径.

图的遍历问题最注重的应该是效率,因此每次在做决策之前应先计算一下遍历所需的时间以及空间大小(非常容易炸掉),如果不行,再想办法优化或者更换方法.

对于图的拓扑排序以及欧拉遍历等问题,将在后继推出.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值