【图的存储】

【图的存储】

邻接表/邻接矩阵

※用来存有向图
无向图:一种特殊的有向图->存两次

add(a,b);
add(b,a);

代码实现:链式前向星

头插法

image

【插入】

int idx=0; //节点序号
int h[M];//头结点:记得初始化为-1!
int e[M];//存储该节点的值 
int ne[M];//存储该节点的下一个点的位置

//x所对应的单链表中插入y x为根结点 
void add(int x,int y){
    e[idx]=y;
    ne[idx]=h[x];
    h[x]=idx++;
}

【遍历】

for(int i=h[u];i!=-1;i=ne[i]){
    int j=e[i]; 
    if(!st[j]){
        
    }
}

如果题目只和边有关系:不一定非得要链式前向星

直接vector<int> g[N]存即可

[例题]Remove Exactly Two

https://codeforces.com/contest/2063/problem/C

#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
vector<int> g[N];//直接使用存儿子的邻接表即可! 
int deg[N];
void solve() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        g[i].clear();
        deg[i] = 0;
    }
    for (int i = 0; i < n - 1; i++) {
        int u, v;
        cin >> u >> v;
        u--; v--;  // 为了方便从0开始编号
        g[u].push_back(v);
        g[v].push_back(u);
        deg[u]++;
        deg[v]++;
    }
    int ans = 0;
    multiset<int> s;
    for (int j = 0; j < n; j++) {
            s.insert(deg[j]);
        }
    for (int i = 0; i < n; i++) {
        s.erase(s.find(deg[i]));
        s.insert(0);
        for (int j : g[i]) {
            s.erase(s.find(deg[j]));
            s.insert(deg[j] - 1);
        }
        int maxDeg = *s.rbegin();
        ans = max(ans, deg[i] + maxDeg - 1);
        s.erase(s.find(0));
        s.insert(deg[i]);
        for (int j : g[i]) {
            s.erase(s.find(deg[j]-1));
            s.insert(deg[j]);
        }
    }
    cout << ans << endl;
}
int main() {
	ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

[例题]树的重心

https://www.acwing.com/problem/content/848/
【样例】
image
【dfs过程】
image

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=N*2;//存无向图:节点数要*2
int n;
//邻接表存储图 
int h[M];//头结点 
int e[M];//存储该节点的值->原先的编号
int ne[M];//存储该节点的下一个点的位置
int idx=0; 

bool st[M];//标记这个点有没有被走过:dfs每个点只会走1次 
int ans=N; 

//x所对应的单链表中插入y x为根结点 
void add(int x,int y){
    e[idx]=y;
    ne[idx]=h[x];
    h[x]=idx++;
}
int dfs(int u){
    int res=0;//删掉某个节点后,最大的连通块节点数 
    st[u]=true;//标记这个点被走过 
    int sum=1;//以u为根节点的树的节点数->包括u所以初始化为1
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];//这里的值->树原先的编号
        if(!st[j]){
            int s=dfs(j);//递归找子树 
            res=max(res,s);
            sum+=s;//以j为根的树 的节点数 
        }
    }
    //父节点所连通块的节点数:n-sum 
    res=max(res,n-sum);
    ans=min(ans,res);
    return sum;//递归找子树需要返回的节点值 
}
int main(){
    scanf("%d",&n);
    memset(h,-1,sizeof h);//头结点初始化为-1
    //不用初始化ne:在插入的过程中就可以自动变为-1了 
    for(int i=0;i<n-1;i++){//【无环图】n-1行数据:n个节点 n-1条边 
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);//无向图是一种特殊的有向图->插入两次 
    }
    dfs(1);
    printf("%d",ans);
    return 0;
}
posted @ 2024-12-12 02:24  White_ink  阅读(53)  评论(0)    收藏  举报