昨天组队赛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个点,却只给你两条边,此时二维数组的空间就会被极大的浪费掉,所以要谨慎使用。