2022.1.20(二叉树&并查集)

目录

P4913 【深基16.例3】二叉树深度

题目描述

输入格式

输出格式

输入输出样例

思路

代码实现

P1229 遍历问题

题目描述

输入格式

输出格式

输入输出样例

思路

代码实现

P1455 搭配购买

题目描述

输入格式

输出格式

输入输出样例

说明/提示

 思路

P2078 朋友

题目背景

题目描述

输入格式

输出格式

输入输出样例

思路

代码实现


刷题!刷题!

P4913 【深基16.例3】二叉树深度

题目描述

给出每个节点的两个儿子节点,建立一棵二叉树(根节点为 11),如果是叶子节点,则输入0 0。建好树后希望知道这棵二叉树的深度。二叉树的深度是指从根节点到叶子结点时,最多经过了几层。

最多有 10^6106 个结点。

输入格式

输出格式

输入输出样例

输入 #1复制

7
2 7
3 6
4 5
0 0
0 0
0 0
0 0

输出 #1复制

4

思路

1、用数组结构体把每个节点的左右孩子都存下来

2、从根节点1开始深搜,用两个参数k,deep分别代表当前节点和当前深度

3、ans(全局变量)代表当前最大深度

4、每次进入函数都比较当前ans和deep的大小,取较大者

5、进入函数后先深搜左子树,再深搜右子树

6、最后输出ans即可

代码实现

#include<bits/stdc++.h>
using namespace std;
int n,ans=0;
struct node{
	int l,r;
}a[10000000];
void dfs(int k,int deep)
{
	if(k==0) return;
	ans=max(ans,deep);
	dfs(a[k].l ,deep+1);
	dfs(a[k].r ,deep+1);
}

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i].l >>a[i].r ;
	}
	dfs(1,1);
	cout<<ans;
	return 0;	
}

P1229 遍历问题

题目描述

我们都很熟悉二叉树的前序、中序、后序遍历,在数据结构中常提出这样的问题:已知一棵二叉树的前序和中序遍历,求它的后序遍历,相应的,已知一棵二叉树的后序遍历和中序遍历序列你也能求出它的前序遍历。然而给定一棵二叉树的前序和后序遍历,你却不能确定其中序遍历序列,考虑如下图中的几棵二叉树:

所有这些二叉树都有着相同的前序遍历和后序遍历,但中序遍历却不相同。

输入格式

输A数据共两行,第一行表示该二叉树的前序遍历结果s1,第二行表示该二叉树的后序遍历结果s2。

输出格式

输出可能的中序遍历序列的总数,结果不超过长整型数。

输入输出样例

输入 #1复制

abc                           
cba

输出 #1复制

4

思路

1、 在一棵树上若有一个结点是只有一个子结点的那么这个子结点在左在右不影响先序后序的遍历顺序

2、用ans计数只有一个子结点的结点

2、中序遍历的种数为 2^ans 

代码实现

#include<bits/stdc++.h>
using namespace std;
int ans=0;
char a[1000],b[1000];
int main()
{
	cin>>a>>b;
	int len=strlen(a);
	for(int i=0;i<len;i++)
		for(int j=1;j<len;j++)
		{
			if(a[i]==b[j]&&a[i+1]==b[j-1])
				ans++;
		}
	ans=pow(2,ans);
	cout<<ans;
	return 0;
}

P1455 搭配购买

题目描述

明天就是母亲节了,电脑组的小朋友们在忙碌的课业之余挖空心思想着该送什么礼物来表达自己的心意呢?听说在某个网站上有卖云朵的,小朋友们决定一同前往去看看这种神奇的商品,这个店里有 nn 朵云,云朵已经被老板编号为 1,2,3,...,n1,2,3,...,n,并且每朵云都有一个价值,但是商店的老板是个很奇怪的人,他会告诉你一些云朵要搭配起来买才卖,也就是说买一朵云则与这朵云有搭配的云都要买,电脑组的你觉得这礼物实在是太新奇了,但是你的钱是有限的,所以你肯定是想用现有的钱买到尽量多价值的云。

输入格式

第一行输入三个整数,n,m,w

n,m,w,表示有 nn 朵云,mm 个搭配和你现有的钱的数目。

第二行至 n+1n+1 行,每行有两个整数, c_i,d_ici​,di​,表示第 ii 朵云的价钱和价值。

第 n+2n+2 至 n+1+mn+1+m 行 ,每行有两个整数 u_i,v_iui​,vi​。表示买第 u_iui​ 朵云就必须买第 v_ivi​ 朵云,同理,如果买第 v_ivi​ 朵就必须买第 u_iui​ 朵。

输出格式

一行,表示可以获得的最大价值。

输入输出样例

输入 #1复制

5 3 10
3 10
3 10
3 10
5 100
10 1
1 3
3 2
4 2

输出 #1复制

1

说明/提示

  • 对于 30\%30% 的数据,满足 1 \le n \le 1001≤n≤100;
  • 对于 50\%50% 的数据,满足 1 \le n,w \le 10^31≤n,w≤103,1 \le m \le 1001≤m≤100;
  • 对于 100\%100% 的数据,满足 1 \le n \le 10^41≤n≤104,0 \le m \le 5 \times 10^30≤m≤5×103

 思路

1、01背包+并查集

2、数组c,d分别存储云朵的价格和价值

3、将m组关系合并(建立家族集合)

4、把将同集合的云朵的价钱与价值都划到一个云朵里(祖先云朵)

	for(int i=1; i<=n; i++) 
	if(fa[i]!=i)
	{
		d[find(i)]+=d[i];
		d[i]=0;
		c[find(i)]+=c[i];
		c[i]=0;
	}

5、用01背包对云朵进行处理;价钱即容量,求最大价值

#include <bits/stdc++.h>
using namespace std;
int n,m,w,t;
int c[10000],d[10000],newc[10000],newd[10000],f[10000],fa[10000];
void work() { //01背包
	for(int i=1; i<=n; i++)
		for(int j=w; j>=c[i]; j--) //滚动数组
			f[j]=max(f[j],f[j-c[i]]+d[i]);
	cout<<f[w];
}
int find(int x) {//查找 
	if(fa[x]==x) return x;
	fa[x]=find(fa[x]);//路径压缩 
	return fa[x];
}
int main() {
	cin>>n>>m>>w;
	for(int i=1; i<=n; i++) {
		cin>>c[i]>>d[i];
		fa[i]=i;//初始化 
	}
	for(int i=1; i<=m; i++) {
		int x,y;
		cin>>x>>y;
		fa[find(x)]=find(y);
	}
	for(int i=1; i<=n; i++) 
	if(fa[i]!=i)
	{
		d[find(i)]+=d[i];
		d[i]=0;
		c[find(i)]+=c[i];
		c[i]=0;
	}
	work();//01背包
	return 0;
}

P2078 朋友

题目背景

小明在 A 公司工作,小红在 B 公司工作。

题目描述

这两个公司的员工有一个特点:一个公司的员工都是同性。

A 公司有 NN 名员工,其中有 PP 对朋友关系。B 公司有 MM 名员工,其中有 QQ 对朋友关系。朋友的朋友一定还是朋友。

每对朋友关系用两个整数 (X_i,Y_i)(Xi​,Yi​) 组成,表示朋友的编号分别为 X_i,Y_iXi​,Yi​。男人的编号是正数,女人的编号是负数。小明的编号是 11,小红的编号是 -1−1。

大家都知道,小明和小红是朋友,那么,请你写一个程序求出两公司之间,通过小明和小红认识的人最多一共能配成多少对情侣(包括他们自己)。

输入格式

输入的第一行,包含 44 个空格隔开的正整数 N,M,P,QN,M,P,Q。

之后 PP 行,每行两个正整数 X_i,Y_iXi​,Yi​。

之后 QQ 行,每行两个负整数 X_i,Y_iXi​,Yi​。

输出格式

输出一行一个正整数,表示通过小明和小红认识的人最多一共能配成多少对情侣(包括他们自己)。

输入输出样例

输入 #1复制

4 3 4 2
1 1
1 2
2 3
1 3
-1 -2
-3 -3

输出 #1复制

2

思路

1、因为女生用的是负数表示,所以要想操作,必须进行转化;因为前n个数是男生,所以用n+1~n+m代表女生

2、很明显题目考察的是并查集,所以先对1~n+m进行初始化

3、接下来p组操作对男生的关系进行合并

4、q组操作对女生的关系进行合并

如何让女生的负数转化成正数,(如第一步所述),操作如下:
    while(q--)//合并 
	{
		int x,y;
		cin>>x>>y;
		x=x*(-1)+n;
		y=y*(-1)+n;
		if(find(x)!=find(y))
			fa[find(x)]=find(y);
	}

5、计数是小明朋友的男生sum1;计数是小红朋友的女生sum2;取两者中较小值即答案

代码实现

#include<bits/stdc++.h>
using namespace std;
int n,m,p,q,sum=0,sum1=0,sum2=0;
int fa[100000];
int find(int i)
{
	if(fa[i]==i)
		return fa[i];
	return find(fa[i]);
}
int main()
{
	cin>>n>>m>>p>>q;
	for(int i=1;i<=n+m;i++)
		fa[i]=i;//初始化 
	while(p--)//合并 
	{
		int x,y;
		cin>>x>>y;
		if(find(x)!=find(y))
			fa[find(x)]=find(y);
	}
	while(q--)//合并 
	{
		int x,y;
		cin>>x>>y;
		x=x*(-1)+n;
		y=y*(-1)+n;
		if(find(x)!=find(y))
			fa[find(x)]=find(y);
	}
	for(int i=1;i<=n;i++)
	{
		if(find(i)==find(1))
			sum1++;
	}
	for(int i=n+1;i<=n+m;i++)
	{
		if(find(i)==find(n+1))
			sum2++;
	}
	sum=min(sum1,sum2);
	cout<<sum;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值