关于邻接链表的一些粗略理解

昨天组队赛WA了一道水题,补题的时候偶然发现了邻接链表里的一些东西,在这里分享一下。(大佬自动忽略)
一、邻接链表
邻接链表也叫邻接表(一直以为这是两种东西,大哭),至于为什么称为链表这里给出了详细解释,https://baike.baidu.com/item/%E9%82%BB%E6%8E%A5%E8%A1%A8/9796152?fr=aladdin
虽然都知道,但还是给出最平常的邻接表的定义方式:vector<\int> G【MAX_V】;(斜线请忽略).
上面的链接中还给出了其余两种表示方法,但个人认为都不如这一种书写简单,但是思路很好,可以了解一下;
下面,介绍邻接链表的主角,链式前向星:详解见 https://blog.csdn.net/acdreamers/article/details/16902023/
对这个东东稍微做一点补充,邻接表适合用于边数较少的情况,链式前向星在做题中的应用很多,而且会很大的提高代码的运行效率,所以当代码超时,而又没有问题可寻时,不如试着去用链式前项星,优化自己的代码。(惨痛的教训)

下面给出一道例题(当然做法并不唯一,但是如果使用DFS,不配合前向星,可能会出现TLE的结果)
题目链接 : https://vjudge.net/problem/HDU-5438
(PS:下面还有关于邻接矩阵的一丢丢的解释)

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define mod 1000000007
#define lowbit(x) (x&(-x))
#define mem(a) memset(a,0,sizeof(a))
#define FRER() freopen("in.txt","r",stdin);
#define FREW() freopen("out.txt","w",stdout);

using namespace std;

typedef pair<int,int> pii;
const int maxn = 100000 + 7 , inf = 0x3f3f3f3f ;
int n,m,nEdge;
int a[maxn];
int vis[maxn],d[maxn];
int head[maxn],nxt[maxn],to[maxn];
void add(int u,int v){
    to[nEdge] = v;
    nxt[nEdge] = head[u];
    head[u] = nEdge++;
}
ll sum;
int cnt;
void dfs(int u){
    cnt++;
    sum+=a[u];
    vis[u] = 1;
    for(int i = head[u];~i;i=nxt[i]){
        int v = to[i];
        if(!vis[v]){
            dfs(v);
        }
    }
    return;
}
void Init(){
    memset(head,-1,sizeof(head));
    mem(nxt);mem(vis);mem(d);mem(to);mem(a);
    nEdge = cnt = 0;
}
int main(){
    //FRER();
    int T;
    scanf("%d",&T);
    while(T--){
        Init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
            d[u]++;
            d[v]++;
        }
        queue<int>q;
        for(int i=1;i<=n;i++)
            if(d[i]<2){
                vis[i]=1;
                q.push(i);
            }
        while(!q.empty()){
            int now = q.front();q.pop();
            for(int i = head[now];~i;i=nxt[i]){
                int v = to[i];
                if(!vis[v]&&--d[v]<2){
                        vis[v]=1;
                   q.push(v);
                }
            }
        }
        ll ans = 0;
        for(int i=1;i<=n;i++){
            if(!vis[i]){
                sum = 0;
                cnt = 0;
                dfs(i);
                if(cnt%2==1)
                    ans+=sum;
            }
        }
        cout<<ans<<endl;
    }
}

二、邻接矩阵
这里只是稍微提一下,因为邻接矩阵书写较为死板,就是一个二维数组,int G【MAX_V】【MAX_V】,但是在遇到输入的边较多的时候,邻接矩阵会展现出无与伦比的优势,而当边数较少的时候,比如给你1e6个点,却只给你两条边,此时二维数组的空间就会被极大的浪费掉,所以要谨慎使用。

猜你喜欢

转载自blog.csdn.net/NCC__dapeng/article/details/81783187