邻接表树和图的基于链表的DFS

 

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100010, M = 2 * N;
int n, ans = N;
int h[N], e[M], ne[M], idx;//n个单链表的头h[N];
bool st[N];
void insert(int a, int b)//插入以a为起点指向b的邻接表,插在a指向链表的开始位置h[a]
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
int dfs(int u)
{
    st[u] = true;=
    int sum = 1, res = 0;//sum子树节点总数,初始化为根节点自己一个,res表示剩下连通块的大小,即所求
    for(int i = h[u]; i != -1;i = ne[i])
    {
        int j = e[i];
        if(!st[j])
        {
            int s = dfs(j);//以u为根节点子树的大小
            res = max(s, res);//每求得一个子树的大小,放入预定的最小池子里面
            sum += s;//把u的每个子树的大小加到s里面,得到的就是u为根的子树的大小,剩下的就是: n - s
        }
    }
    res = max(res, n - sum);//先求得去掉某一个数 剩余连通块的最大值
    
    ans = min(ans, res);//去掉n个数每一个数之后所剩连通块最大值的最小。
    
    return sum;
}
int main()
{
    memset(h, - 1, sizeof h);
    cin>>n;
    for(int i = 0;i<n-1;i++)
    {
        int a,b;
        cin>>a>>b;
        insert(a, b), insert(b,a);//无向边,需要加入b->a, a->b。
    }
    dfs(1);//假定1位根,搜索起点
    cout<<ans<<endl;
    return 0;
}

 如果在dfs后面加一行打印的话:

9

1 2

1 7

1 4

2 8

2 5

4 3

3 9

4 6

j:  6sum: 1

j:  9sum: 1

j:  3sum: 2

j:  4sum: 1

j:  7sum: 5

j:  5sum: 1

j:  8sum: 2

j:  2sum: 6

4

Program ended with exit code: 0

可以发现根据递归式栈的特点,最后进入的最先算出来,所以是DFS的逆序输出结果。

 

 重心 子树大小 结点

res 8 sum: 1   6

 res 8 sum: 1  9

 res 7 sum: 2  3

 res 5 sum: 4  4

 res 8 sum: 1  7

 res 8 sum: 1  5

 res 8 sum: 1  8

 res 6 sum: 3  2

 res 4 sum: 9  1

4

可以看到打印输出的结果是跟递归的顺序刚好相反的:

递归顺序是:1 2 8 5 7 4 3 9 6 

返回顺序是:6 9 3 4 7 5 8 2 1

子树sum值:1  1 2 4 1  1 1  3 9

然后所求res: 8 8 7 5 8 8 8 6 4 最小的就是4.

posted @ 2020-04-14 14:28  龙雪可可  阅读(183)  评论(0编辑  收藏  举报
****************************************** 页脚Html代码 ******************************************