天梯赛 L2-012 关于堆的判断

将一系列给定数字顺序插入一个初始为空的小顶堆H[]。随后判断一系列相关命题是否为真。命题分下列几种:

  • x is the rootx是根结点;
  • x and y are siblingsxy是兄弟结点;
  • x is the parent of yxy的父结点;
  • x is a child of yxy的一个子结点。

输入格式:

每组测试第1行包含2个正整数N(≤ 1000)和M(≤ 20),分别是插入元素的个数、以及需要判断的命题数。下一行给出区间[−10000,10000]内的N个要被插入一个初始为空的小顶堆的整数。之后M行,每行给出一个命题。题目保证命题中的结点键值都是存在的。

输出格式:

对输入的每个命题,如果其为真,则在一行中输出T,否则输出F

输入样例:

5 4
46 23 26 24 10
24 is the root
26 and 23 are siblings
46 is the parent of 23
23 is a child of 10

输出样例:

F
T
F
T

AC代码:

#include<bits/stdc++.h>
#include<unordered_map> 
#include<unordered_set>
using namespace std;
#define int long long //可能会超时 
#define PII pair<int,int>
const int INF = 0x3f3f3f3f, mod = 998244353;
const int N = 1005;
int heap[N], n, m;
int cnt;
void down(int u) {
	int t = u;
	if (u * 2 <= cnt && heap[u * 2] < heap[t]) t = u * 2;
	if (u * 2 + 1 <= cnt && heap[u * 2 + 1] < heap[t]) t = u * 2 + 1;
	if (t - u) {
		swap(heap[t], heap[u]);
		down(t);
	}
}
void up(int u) {
	while (u / 2 && heap[u / 2] > heap[u]) {
		swap(heap[u / 2], heap[u]);
		u /= 2;
	}
}
signed main()
{
	ios::sync_with_stdio, cin.tie(0), cout.tie(0);
	cin >> n >> m;
	getchar();
	while (n--) {
		int x;
		cin >> x;
		getchar();
		heap[++cnt] = x;
		up(cnt);
	}
	while (m--) {
		string s;
		getline(cin, s);
		if (s.back() == 's') {
			string first, second;
			for (int i = 0;i < s.size();i++) {
				if (s[i] == ' ') break;
				first += s[i];
			}
			int d = 0;
			for (int i = 0;i < s.size();i++) {
				if (s[i] == 'd') d = i;
			}
			for (int i = d + 2;s[i] != 'a';i++) second += s[i];
			int f1 = stoi(first), f2 = stoi(second),f11,f22;
			for (int i = 1;i <= cnt;i++) {
				if (f1 == heap[i]) f11 = i;
				if (f2 == heap[i]) f22 = i;
			}
			if ((f11 - f22 == 1 && f11 & 1) || (f22 - f11 == 1 && f22 & 1)) puts("T");
			else puts("F");
		}
		else if (s.back() == 't') {
			string first;
			for (int i = 0;i < s.size();i++) {
				if (s[i] == ' ') break;
				first += s[i];
			}
			int x = stoi(first);
			if (heap[1] == x) puts("T");
			else puts("F");
		}
		else {
			int flag = 0;
			for (auto i : s) {
				if (i == 'p') {
					flag = 1;
					break;
				}
			}
			if (flag) {
				string first, second;
				for (int i = 0;i < s.size();i++) {
					if (s[i] == ' ') break;
					first += s[i];
				}
				for (int i = s.size() - 1;i >= 0;i--) {
					if (s[i] == ' ') break;
					second += s[i];
				}
				reverse(second.begin(), second.end());
				int x = stoi(first), y = stoi(second);
				int x1, y1;
				for (int i = 1;i <= cnt;i++) {
					if (heap[i] == x) x1 = i;
					if (heap[i] == y) y1 = i;
				}
				x1 == y1 / 2 ? puts("T") : puts("F");
			}
			else {
				string first, second;
				for (int i = 0;i < s.size();i++) {
					if (s[i] == ' ') break;
					first += s[i];
				}
				for (int i = s.size() - 1;i >= 0;i--) {
					if (s[i] == ' ') break;
					second += s[i];
				}
				reverse(second.begin(), second.end());
				int x = stoi(first), y = stoi(second);
				int x1, y1;
				for (int i = 1;i <= cnt;i++) {
					if (heap[i] == x) x1 = i;
					if (heap[i] == y) y1 = i;
				}
				if (x1 == y1 * 2 || x1 == y1 * 2 + 1) puts("T");
				else puts("F");
			}
		}
	}
	return 0;
}

   题意不难理解,从定义出发,用一个一维数组heap存堆的所有元素,判断是否是根结点只需判断x是否等于heap[1]即可。判断兄弟结点通过找规律可发现,x和y是兄弟结点当且仅当x和y在堆中对应的下标差值为1且奇数大。判断父结点和子结点类似,判断对应下标是否等于x/2或x*2或x*2+1。

(趁这几天没事把一直不怎么懂的堆学了,算是了结一桩心事吧。。。)

### 关于数据结构判断问题及其Java实现 #### 定义与特性 是一种特殊的完全二叉树,分为最大和最小两种形式。对于最大而言,任意节点的键值总是大于等于其子节点的键值;而对于最小,则相反,即任意节点的键值小于等于其子节点的键值[^1]。 #### PTA L2-012 判断逻辑解析 针对L2-012中的具体需求,程序需接收一组整数作为输入并构建相应的最小或最大(取决于题目要求),之后依据特定条件验证若干命题的真实性。这些命题涉及根节点、兄弟关系、父子关系等方面的内容[^4]。 #### Java代码实例展示 下面给出一段用于解决上述问题的核心部分——向已有的最小中插入新元素,并提供辅助函数来执行各种类型的查询: ```java import java.util.*; public class MinHeap { private List<Integer> heap; public MinHeap() { this.heap = new ArrayList<>(); // 初始化时加入哨兵元素以便简化索引计算 this.heap.add(Integer.MIN_VALUE); } /** * 向最小内添加新的数值 */ public void insert(int value){ int index = heap.size(); heap.add(value); while (index / 2 > 0 && heap.get(index/2) > heap.get(index)){ swap(index, index/2); index /= 2; } } /** * 获取指定位置处的左孩子下标 */ private static int getLeftChildIndex(int parentIndex){ return parentIndex*2; } /** * 获取指定位置处的右孩子下标 */ private static int getRightChildIndex(int parentIndex){ return parentIndex*2 + 1; } /** * 判断两个给定的位置是否互为兄弟节点 */ public boolean areSiblings(int x, int y){ if(x <= 0 || y <= 0 || x >= heap.size() || y >= heap.size()) throw new IndexOutOfBoundsException(); return getParentIndex(x)==getParentIndex(y)&&x!=y; } /** * 返回某节点的父亲节点所在数组里的序号 */ private static int getParentIndex(int childIndex){ return childIndex/2; } /** * 查询某个数字是不是当前顶元素 */ public boolean isRoot(int target){ return !heap.isEmpty()&&target==heap.get(1); } /** * 验证是否存在这样的亲子关系:parent->child */ public boolean hasParentChildRelation(int parent,int child){ if(child<=0||parent<=0||child>=heap.size()||parent>=heap.size()) throw new IndexOutOfBoundsException(); return getParentIndex(child)==parent; } /** * 执行交换操作 */ private void swap(int i, int j){ Collections.swap(heap,i,j); } } ``` 这段代码实现了基本的小根功能,包括但不限于插入新成员、查找根节点、确认两节点间的关系等常用方法。通过调用`insert()`可以逐步建立起所需的结构,而其他几个公开的方法则可用于完成后续的各种检验工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值