• 树&图总结


    定义

    树(tree)是包含n(n>=1)个结点,(n-1)条边的有穷集,其中:

    (1)每个元素称为结点(node);

    (2)有一个特定的结点被称为根结点或树根(root)。

    (3)除根结点之外的其余数据元素被分为m(m≥0)个互不相交的集合T1,T2,……Tm-1,其中每一个集合Ti(1<=i<=m)本身也是一棵树,被称作原树的子树(subtree)。

    树也可以这样定义:树是由根结点和若干颗子树构成的。树是由一个集合以及在该集合上定义的一种关系构成的。集合中的元素称为树的结点,所定义的关系称为父子关系。父子关系在树的结点之间建立了一个层次结构。在这种层次结构中有一个结点具有特殊的地位,这个结点称为该树的根结点,或称为树根。

    我们可以形式地给出树的递归定义如下:

    单个结点是一棵树,树根就是该结点本身。

    设T1,T2,..,Tk是树,它们的根结点分别为n1,n2,..,nk。用一个新结点n作为n1,n2,..,nk的父亲,则得到一棵新树,结点n就是新树的根。我们称n1,n2,..,nk为一组兄弟结点,它们都是结点n的子结点。我们还称T1,T2,..,Tk为结点n的子树。

    空集合也是树,称为空树。空树中没有结点。

    结点的度:一个结点含有的子结点的个数称为该结点的度;

    叶结点或终端结点:度为0的结点称为叶结点;

    非终端结点或分支结点:度不为0的结点;

    双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点;

    孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点;

    兄弟结点:具有相同父结点的结点互称为兄弟结点;

    树的度:一棵树中,最大的结点的度称为树的度;

    结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推;

    树的高度或深度:树中结点的最大层次;

    堂兄弟结点:双亲在同一层的结点互为堂兄弟;

    结点的祖先:从根到该结点所经分支上的所有结点;

    子孙:以某结点为根的子树中任一结点都称为该结点的子孙。

    森林:由m(m>=0)棵互不相交的树的集合称为森林;

    存储方式及模板

    动态数组(常用)

    cin>>n;
    for(int i=1;i<=n;i++){
    	cin>>u>>v;
    	g[u].push_back(v);
    	g[v].push_back(u);
    }
    

    邻接矩阵(常用于传递闭包)

    cin>>n;
    for(int i=1;i<=n;i++){
    	cin>>u>>v;
    	g[u][v]=true;
    }
    

    例题

    #10032. 二叉树的序遍历

    思路

    使用dfs遍历整棵树,再将dfs序输出(前序则最先输出,中序于中间输出,后序则最后输出,符合根左右、左根右和左右根的顺序

    Code

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int l,r;
    vector<int>v[30];
    //第一次写代码的时候函数调用错了,故一定要注意细节qwq
    void dfs(int x){//前序遍历
    	if(x==0)return;
    	cout<<x<<" ";
    	dfs(v[x][0]);
    	dfs(v[x][1]);
    }
    void dfs1(int x){//中序遍历
    	if(x==0)return;
    	dfs1(v[x][0]);
    	cout<<x<<" ";
    	dfs1(v[x][1]);
    }
    void dfs2(int x){//后序遍历
    	if(x==0)return;
    	dfs2(v[x][0]);
    	dfs2(v[x][1]);
    	cout<<x<<" ";
    }
    int main(){
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		cin>>l>>r;
    		v[i].push_back(l);
    		v[i].push_back(r);
    	}
    	dfs(1);//从根结点开始遍历(题目中说了根结点一定为1)
    	cout<<endl;
    	dfs1(1);
    	cout<<endl;
    	dfs2(1); 
    	return 0;
    }
    

    #10033. 二叉树的叶节点和

    思路

    由于叶结点的特点是,除了根结点外,度数必为1,则可编写代码

    Code

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int l,r;
    int a[10000010];
    int ans;
    int main(){
    	cin>>n;
    	if(n==1){
    		cout<<1;
    		return 0;
    	}
    	for(int i=1;i<=n;i++){
    		cin>>l>>r;
    		if(l!=0){
    			a[l]++;
    			a[i]++;
    		}
    		if(r!=0){
    			a[r]++;
    			a[i]++;
    		}
    	}
    	//之前这里就因把根结点算了进去,所以这里要注意qwq
    	for(int i=2;i<=n;i++){
    		if(a[i]==1){
    			ans+=i;
    		}
    	}
    	cout<<ans;
    	return 0;
    }
    

    #210756. 树上两点距离

    思路

    可以使用dfs遍历全树,如到了给定的结束点,则保存深度并回溯

    Code

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int x,y;
    int a,b,ans;
    vector<int>nodes[1010];
    void dfs(int x,int from,int dep){
    	if(x==b){
    		ans=dep;
    		return;
    	}
    	int len=nodes[x].size();
    	for(int i=0;i<len;i++){
    		int v=nodes[x][i];
    		if(v!=from){
    			dfs(v,x,dep+1);
    		}
    	}
    }
    int main(){
    	cin>>n;
    	for(int i=1;i<n;i++){
    		cin>>x>>y;
    		nodes[x].push_back(y);
    		nodes[y].push_back(x);
    	}
    	cin>>a>>b;
    	dfs(a,0,0);
    	cout<<ans;
    	return 0;
    }
    

    #210777. 树的深度

    思路

    直接使用dfs遍历全树,每进入一次dfs,就进行ans=max(ans,dep),最后输出ans即可

    Code

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int x,y;
    int a[1010],b,ans;
    vector<int>nodes[1010];
    void dfs(int x,int from,int dep){
    	ans=max(ans,dep);
    	int len=nodes[x].size();
    	for(int i=0;i<len;i++){
    		int v=nodes[x][i];
    		if(v!=from){
    			dfs(v,x,dep+1);
    		}
    	}
    }
    int main(){
    	cin>>n;
    	for(int i=1;i<n;i++){
    		cin>>x>>y;
    		nodes[x].push_back(y);
    		nodes[y].push_back(x);
    	}
    	dfs(1,0,1);
    	cout<<ans;
    	return 0;
    }
    

    #210776. 每个点的子树大小

    思路

    使用dfs遍历树,如果符合遍历条件,则使用f数组记录每个结点的子树的结点数(f数组初始化为1)

    Code

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int x,y;
    vector<int>nodes[1010];
    int f[1010];
    void dfs(int x,int from){
    	int len=nodes[x].size();
    	for(int i=0;i<len;i++){
    		int v1=nodes[x][i];
    		if(v1!=from){
    			dfs(v1,x);
    			f[x]+=f[v1];
    		}
    	}
    }
    int main(){
    	cin>>n;
    	for(int i=1;i<n;i++){
    		cin>>x>>y;
    		nodes[x].push_back(y);
    		nodes[y].push_back(x);
    	}
    	for(int i=1;i<=n;i++){
    		f[i]=1;
    	}
    	dfs(1,0);
    	for(int i=1;i<=n;i++){
    		cout<<f[i]<<" ";
    	} 
    	return 0;
    }
    

    定义

    图论〔Graph Theory〕是数学的一个分支。它以图为研究对象。图论中的图是由若干给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物间具有这种关系。

    存储方式及模板

    动态数组(常用)

    cin>>n;
    for(int i=1;i<=n;i++){
    	cin>>u>>v;
    	g[u].push_back(v);
    	g[v].push_back(u);
    }
    

    邻接矩阵(常用于传递闭包)

    cin>>n;
    for(int i=1;i<=n;i++){
    	cin>>u>>v;
    	g[u][v]=true;
    }
    

    由上,我们可以发现图的存储方式与树的存储方式一致,我们称之为树图同存


    例题

    #1612. 【Usaco2008 Jan】 Cow Contest奶牛的比赛

    思路

    一道使用传递闭包解决的典型题目

    Code

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,a,b,ans;
    bool f[110][110];
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=m;i++){
    		cin>>a>>b;
    		f[a][b]=true;
    	}
    	for(int k=1;k<=n;k++){
    		for(int i=1;i<=n;i++){
    			for(int j=1;j<=n;j++){
    				f[i][j]|=f[i][k]&f[k][j];
    			}
    		}
    	}
    	for(int i=1;i<=n;i++){
    		int x=0;
    		int y=0;
    		for(int j=1;j<=n;j++){
    			if(f[j][i])x++;
    			if(f[i][j])y++;
    		}
    		if(x+y==n-1)ans++;
    	}
    	cout<<ans;
    	return 0;
    }
    

    #10068. 珍珠

    思路

    使用传递闭包,最后统计如果某一颗珍珠的重量关系不在中间,则计数器++,最后输出计数器即可

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int N=110;
    int g[N][N],cnt;
    int main(){
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=m;i++){
            int x,y;
            cin>>x>>y;
            g[x][y]=true;
        }
    	for(int k=1;k<=n;k++){
    		for(int i=1;i<=n;i++){
    			for(int j=1;j<=n;j++){
    				g[i][j]|=g[i][k]&g[k][j];
    			}
    		}
    	}
        for(int i=1;i<=n;i++){
        	for(int j=1;j<=n;j++){
                g[0][j]+=g[i][j];
                g[i][0]+=g[i][j];
            }
    	}
        for(int i=1;i<=n;i++){
        	if(g[0][i]>n/2||g[i][0]>n/2){
            	cnt++;
    		}
    	}
        cout<<cnt;
    	return 0;
    }
    

    #10292. 刻录光盘

    思路

    通过传递闭包将子树合并到一起,最后输出根结点个数

    Code

    #include<bits/stdc++.h>
    using namespace std;
    int u,v,ans,n,a[1010];
    bool f[1010][1010];
    int main() {
        cin>>n;
        for(int i=1;i<=n;i++){
    		int j=0;
    		do{
    			cin>>j;
    			if(j==0)break;
    			f[i][j]=true; 
    		}while(j!=0);
        }
    	for(int k=1;k<=n;k++){//传递闭包
    		for(int i=1;i<=n;i++){
    			for(int j=1;j<=n;j++){
    				f[i][j]|=f[i][k]&f[k][j];
    			}
    		}
    	}
    	for(int i=1;i<=n;i++)a[i]=i;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=n;j++){
    			if(f[i][j]){
    				a[j]=a[i];
    			}
    		}
    	}
    	for(int i=1;i<=n;i++){
    		if(a[i]==i){
    			ans++;
    		}
    	}
    	cout<<ans;
    	return 0;
    }
    

    #10126. 图的连通块

    思路

    使用dfs遍历全图,如未被遍历过,则计数器++,并使用dfs继续遍历,与二维数组使用dfs求连通块十分相似

    Code

    #include<bits/stdc++.h>
    using namespace std;
    int u,v,ans;
    bool vis[10010];
    vector<int>g[10010];
    void dfs(int x){
    	vis[x]=true;
    	int len=g[x].size();
    	for(int i=0;i<len;i++){
    		int v=g[x][i];
    		if(!vis[v]){
    			dfs(v);
    		}
    	}
    }
    int main() {
        int m,n,count,num;
        cin>>n>>m;
        for (int i = 1; i <= m; i++) {
            cin>>u>>v;
            g[u].push_back(v);
            g[v].push_back(u);
        }
        for(int i=1;i<=n;i++){
        	if(!vis[i]){
        		ans++;
        		dfs(i);
    		}
    	}
    	cout<<ans; 
    	return 0;
    }
    
    她透过我的血,看到了另一抹殷红
  • 相关阅读:
    两个不同于LR和jmeter的性能测试工具
    一个基于集成jenkins的测试平台
    sparkR原理
    Python 出现需要使用fPIC重新编译的问题
    eclipse中使用jython
    R中逻辑运算
    R语言的一些笔记
    Distributed R
    R语言和大数据
    Mysql command line
  • 原文地址:https://www.cnblogs.com/zhangbeini/p/13543182.html
Copyright © 2020-2023  润新知