树和图的遍历与搜索

1.树的重心 acwing 846

复制代码
 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 
 7 const int N = 1e5 + 10; //数据范围是10的5次方
 8 const int M = 2 * N; //以有向图的格式存储无向图,所以每个节点至多对应2n-2条边
 9 
10 int h[N]; //邻接表存储树,有n个节点,所以需要n个队列头节点
11 int e[M]; //存储元素
12 int ne[M]; //存储列表的next值
13 int idx; //单链表指针
14 int n; //题目所给的输入,n个节点
15 int ans = N; //表示重心的所有的子树中,最大的子树的结点数目
16 
17 bool st[N]; //记录节点是否被访问过,访问过则标记为true
18 
19 //a所对应的单链表中插入b  a作为根 
20 void add(int a, int b) {
21     e[idx] = b, ne[idx] = h[a], h[a] = idx++;
22 }
23 
24 // dfs 框架
25 /*
26 void dfs(int u){
27     st[u]=true; // 标记一下,记录为已经被搜索过了,下面进行搜索过程
28     for(int i=h[u];i!=-1;i=ne[i]){
29         int j=e[i];
30         if(!st[j]) {
31             dfs(j);
32         }
33     }
34 }
35 */
36 
37 //返回以u为根的子树中节点的个数,包括u节点
38 int dfs(int u) {
39     int res = 0; //存储 删掉某个节点之后,最大的连通子图节点数
40     st[u] = true; //标记访问过u节点
41     int sum = 1; //存储 以u为根的树 的节点数, 包括u,如图中的4号节点
42 
43     //访问u的每个子节点
44     for (int i = h[u]; i != -1; i = ne[i]) {
45         int j = e[i];
46         //因为每个节点的编号都是不一样的,所以 用编号为下标 来标记是否被访问过
47         if (!st[j]) {
48             int s = dfs(j);  // u节点的单棵子树节点数 如图中的size值
49             res = max(res, s); // 记录最大联通子图的节点数
50             sum += s; //以j为根的树 的节点数
51         }
52     }
53 
54     //n-sum 如图中的n-size值,不包括根节点4;
55     res = max(res, n - sum); // 选择u节点为重心,最大的 连通子图节点数
56     ans = min(res, ans); //遍历过的假设重心中,最小的最大联通子图的 节点数
57     return sum;
58 }
59 
60 int main() {
61     memset(h, -1, sizeof h); //初始化h数组 -1表示尾节点
62     cin >> n; //表示树的结点数
63 
64     // 题目接下来会输入,n-1行数据,
65     // 树中是不存在环的,对于有n个节点的树,必定是n-1条边
66     for (int i = 0; i < n - 1; i++) {
67         int a, b;
68         cin >> a >> b;
69         add(a, b), add(b, a); //无向图
70     }
71 
72     dfs(1); //可以任意选定一个节点开始 u<=n
73 
74     cout << ans << endl;
75 
76     return 0;
77 }
View Code
复制代码

 2.拓扑排序

复制代码
 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N = 100010;
 6 int e[N], ne[N], idx;//邻接表存储图
 7 int h[N];
 8 int q[N], hh = 0, tt = -1;//队列保存入度为0的点,也就是能够输出的点,
 9 int n, m;//保存图的点数和边数
10 int d[N];////保存各个点的入度
11 
12 void add(int a, int b){
13     e[idx] = b, ne[idx] = h[a], h[a] = idx++;
14 }
15 
16 void topsort(){
17     for(int i = 1; i <= n; i++){//遍历一遍顶点的入度。
18         if(d[i] == 0)//如果入度为 0, 则可以入队列
19             q[++tt] = i;
20     }
21     while(tt >= hh){//循环处理队列中点的
22         int a = q[hh++];
23         for(int i = h[a]; i != -1; i = ne[i]){//循环删除 a 发出的边
24             int b = e[i];//a 有一条边指向b
25             d[b]--;//删除边后,b的入度减1
26             if(d[b] == 0)//如果b的入度减为 0,则 b 可以输出,入队列
27                 q[++tt] = b;
28         }
29     }
30     if(tt == n - 1){//如果队列中的点的个数与图中点的个数相同,则可以进行拓扑排序
31         for(int i = 0; i < n; i++){//队列中保存了所有入度为0的点,依次输出
32             cout << q[i] << " ";
33         }
34     }
35     else//如果队列中的点的个数与图中点的个数不相同,则可以进行拓扑排序
36         cout << -1;//输出-1,代表错误
37 }
38 
39 
40 int main(){
41     cin >> n >> m;//保存点的个数和边的个数
42     memset(h, -1, sizeof h);//初始化邻接矩阵
43     while (m -- ){//依次读入边
44         int a, b;
45         cin >> a >> b;
46         d[b]++;//顶点b的入度+1
47         add(a, b);//添加到邻接矩阵
48     }
49     topsort();//进行拓扑排序
50     return 0;
51 }
View Code
复制代码
复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n,m;
 5 const int N =100010;
 6 int h[N],q[N],d[N];
 7 int e[N],ne[N],idx;
 8 
 9 void add(int a,int b)
10 {
11     e[idx] = b;
12     ne[idx] = h[a];
13     h[a] = idx ++;
14 }
15 
16 bool topsort()
17 {
18     int hh = 0, tt = -1;
19 
20     // d[i] 存储点i的入度
21     for (int i = 1; i <= n; i ++ ) //遍历所有的点
22         if (!d[i]) //把所有入度不为0的点插到队列中去
23             q[ ++ tt] = i;
24 
25     while (hh <= tt)
26     {
27         int t = q[hh ++ ]; //取出队头
28 
29         for (int i = h[t]; i != -1; i = ne[i]) //拓展队头元素
30         {
31             int j = e[i]; //找到初边
32             if (-- d[j] == 0) // 入度 --
33                 q[ ++ tt] = j;  //j 编入队列
34         }
35     }
36     // 如果所有点都入队了,说明存在拓扑序列;否则不存在拓扑序列。
37     return tt == n - 1;
38 }
39 
40 
41 int main()
42 {
43     cin >> n >> m;
44     
45     memset(h, -1, sizeof h);
46     
47     for (int i = 0; i < m; i ++ )
48     {
49         int a,b;
50         cin >> a >> b;
51         add(a,b);
52         d[b] ++;
53     }
54     
55     if(topsort())
56     {
57         for (int i = 0; i < n; i ++ ) printf("%d ",q[i]);
58         puts("");
59     }
60     else puts("-1");
61     
62     return 0;
63 }
View Code
复制代码

 

posted @   rw156  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示