Xtu2024程设第三次练习题解

1544.中位数

经过尝试每次pop前sort是会超时的(doge)

双堆维护中位数区域,一个大根堆一个小根堆,自己思考一下就知道思路了

#include<iostream>
#include<queue>
#include<vector>
using namespace std;
priority_queue<int>little;
priority_queue<int,vector<int>,greater<int>>bigger;
void check(){
	if(bigger.size()>little.size()){
		little.push(bigger.top());bigger.pop();
	}else if(little.size()>bigger.size()+1){
		bigger.push(little.top());little.pop();
	}
	if(little.empty()){
		little.push(bigger.top());bigger.pop();
	}
}
int main(){
	char op[6];
	while(scanf("%s",op)!=EOF){
		int x;
		if(op[1] == 'u'){
			scanf("%d",&x);
			if(little.empty() || x<little.top())little.push(x);
			else bigger.push(x);
			check();
		}else{
			int res = little.top();little.pop();
			check();
			printf("%d\n",res);
		}
	}
}

1551.二叉树合并

这里对于建树的节点不能用的时候才创建,因为需要提前根据下标进行左右孩子的指向,所以提前为两棵树的100个节点进行内存分配初始化。

其次,在对于储存前序中序结果的数组中,数组大小一定要能够容纳合并前两棵树所有节点的大小(有可能两棵树除了根节点相同,其它点都错位分布)

#include<iostream>
using namespace std;
struct node {
	int var;
	node*l;
	node*r;
	node(int x): var(x), l(nullptr), r(nullptr) {}
};
node* tree1[110];
node* tree2[110];
node* root;
node* solve(node*a, node*b) {
	if(a == nullptr)return b;
	if(b == nullptr)return a;
	a->var += b->var;
	a->l = solve(a->l, b->l);
	a->r = solve(a->r, b->r);
	return a;
}
void init(){
	for(int i = 1;i<=100;i++){
		tree1[i] = new node(0);
		tree2[i] = new node(0);
	}
}
int cnt;
int arr[210][2];
void pre(node* x){
	if(x == nullptr)return ;
//	printf("%d\n",x->var);
	arr[cnt++][0] = x->var;
	pre(x->l);
	pre(x->r);
}
void mid(node* x){
	if(x == nullptr)return ;
	mid(x->l);
	arr[cnt++][1] = x->var;
	mid(x->r);
}
void output(int k){
	printf("%d",arr[0][k]);
	for(int i = 1;i<cnt;i++)printf(" %d",arr[i][k]);
	printf("\n");
}
int main() {
	init();
	int t;
	scanf("%d", &t);
	while (t--) {
		int n;
		cnt = 0;
		scanf("%d", &n);
		for (int i = 1; i <= n; i++) {
			int l, r;
			scanf("%d%d%d", &tree1[i]->var, &l, &r);
			if (l)tree1[i]->l = tree1[l];
			else tree1[i]->l = nullptr;
			if (r)tree1[i]->r = tree1[r];
			else tree1[i]->r = nullptr;
		}
//		for(int i = 1;i<=n;i++){
//			printf("%d->%d,%d\n",i,tree1[i]->l==nullptr?0:tree1[i]->l->var,tree2[i]->r==nullptr?0:tree1[i]->r->var);
//		}
		scanf("%d", &n);
		for (int i = 1; i <= n; i++) {
			int l, r;
			scanf("%d%d%d", &tree2[i]->var, &l, &r);
			if (l)tree2[i]->l = tree2[l];
			else tree2[i]->l = nullptr;
			if (r)tree2[i]->r = tree2[r];
			else tree2[i]->r = nullptr;
		}
		root = solve(tree1[1], tree2[1]);
		pre(root);
		cnt = 0;
		mid(root);
		output(0);
		output(1);
	}
}

1554.二叉查找树

与其说高度,其实不如说成深度更好理解,因为高度来看根节点应该是最高的,对于这题不是最优思路。

根节点视作深度为1,那么很容易想到新增的深度就是它父节点的深度+1,其他操作就是建一棵BST的基本操作吧,没什么思考量

#include<iostream>
using namespace std;
struct node{
	int var,h;
	node *l;
	node *r;
	node(int v,int h):var(v),h(h),l(nullptr),r(nullptr){}
};
int ans , n;
node *root;
void insert(int cur,node *fa){
	if(cur<fa->var){
		if(fa->l)insert(cur,fa->l);
		else {
			ans += fa->h+1;
			fa->l = new node(cur,fa->h+1);
		}
	}else{
		if(fa->r)insert(cur,fa->r);
		else {
			ans += fa->h+1;
			fa->r = new node(cur,fa->h+1);
		}
	}
}
void build(){
	int x;
	scanf("%d",&x);
	root = new node(x,1);
	for(int i = 1;i<n;i++){
		scanf("%d",&x);
		insert(x,root);
	}
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		ans = 1;
		scanf("%d",&n);
		build();
		printf("%d\n",ans);
	}
}

1557.树

我个人喜欢prim算法一些,只用排序、然后找连通分支,最后取边(最小生成树的套路,只不过每次取边都从大的开始取。

#include<iostream>
#include<algorithm>
using namespace std;
struct node{
	int a,b,w;
};
node v[20010];
int fa[2010];
bool cmp(node a,node b){
	return a.w>b.w;
}
int find(int a){ //找连通分支
//并查集中的递归写法
	if(fa[a] == a)return a;
	fa[a] = find(fa[a]);
	return fa[a];
}
int n,m,all,maxTree;
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		all = maxTree = 0;
		scanf("%d%d",&n,&m);
		for(int i = 0;i<m;i++){
			int a,b,w;
			scanf("%d%d%d",&a,&b,&w);all+=w;
			v[i].a = a;v[i].b = b;v[i].w = w;
			fa[a] = a;fa[b] = b;
            // 初始化每个点的连通分支根为自己(没取这条边的话,这两个点显然暂时不是一个分支)
		}
		sort(v,v+m,cmp);
		int k = 0,cnt = 0;
		while(cnt<n-1){
			int fx = find(v[k].a),fy = find(v[k].b);
			if(fx!=fy){
                // 每次找分支都是递归查询,只需要改根节点间的连通关系,其他相关点在之后的查询中会自动更新
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值