2021-03-05 PAT第一次模拟 范围【1120-1123】

博主分享了PAT模拟考试的经验,重点讨论了A1123题——Is It a Complete AVL Tree。文章提到前两题在40分钟内解决,第三题涉及哈密顿环,通过理解环的特性解答。最后一题是关于AVL树的,强调了AVL树构建和层序遍历的难点,以及判断完全树的方法。并给出了AC代码的关键点。
摘要由CSDN通过智能技术生成

感悟:

  1. 前两题我在40分钟内解决了,但实际上如果仔细一些可以在半小时内完成。
  2. 第三题是判断哈密顿环的问题,有一定的知识背景要求,当然学过图论的应该都知道一些的。
    一开始我还觉得按照PAT的尿性,可能给的无向图的信息都是有迷惑性的,比如可能会有一些孤立点?但是实际上是没有的。
    只要了解到环的特性:环长为点数+1,以及头尾是一样的。以及哈密顿的特性:所有点都经过。那么只剩下一个样例过不了了。
    对于最后一个样例,我们还需要判断题目给出的这个path上那些相邻点是不是连通的,需要根据前面给出的图来进行判断,如果中间有一条边是断开的,那么就NO。
    ac代码:
#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
int M,N;
int G[210][210];
int book[210]={0};
int main(){
    scanf("%d %d",&M,&N);
    for(int i=0,m,n;i<N;i++){
        scanf("%d %d",&m,&n);
        G[m][n] = G[n][m] = 1;
    }
    int K,k,st,ed;
    vector<int> path;
    scanf("%d",&K);
    for(int i=0;i<K;i++){
        path.clear();
        map<int,bool> mp;
        scanf("%d",&k);
        for(int j=0,m;j<k;j++){
            scanf("%d",&m);
            path.push_back(m);
            mp[m] = 1;
            if(j==0)
                st = m;
            if(j==k-1)
                ed = m;
        }
        int j;
        for(j=1;j<path.size();j++){
            if(G[path[j-1]][path[j]]!=1){
                printf("NO\n");
                break;
            }
        }
        if(j!=path.size()){
            continue;
        }
        if(st!=ed){
            printf("NO\n");
            continue;
        }
        for(j=1;j<=M;j++)
            if(mp[j]==0){
                printf("NO\n");
                break;
            }
        if(j!=M+1)
            continue;
        if(k!=M+1){
            printf("NO\n");
            continue;
        }
        printf("YES\n");
    }
}
  1. 最后一题关于AVL的可以说是完全忘记了,还需要多多复习。这里着重讲讲最后这题的思路。

A1123 Is It a Complete AVL Tree ?

首先我们需要AVL建树,建完后再层序遍历。层序遍历不难,但是AVL树怎么建是挺麻烦的。这里有两个注意点:
第一,需要考虑什么时候用引用
将指针看成是一棵树的根结点,如果这颗树的结构(注意是结构而不是值),那么就需要用引用
第二,考虑什么时候updateHeight,即更新结点高度
这里我总结的就是,当一个结点移动过后,那么从下而上的进行更新 即可 !
**注意:insert(root->lchild,data)之后应该updateH(root)而不是root->lchild ! **
因为如果root->lchild本来是NULL,那新节点是完全没有必要更新的,递归次序反而导致最后的root不会被更新。

然后需要判断这是否为一颗完全树,事实上这道题就是两道题的融合hhhh
如何判断树是否完全?
我们可以参考堆,根下标为ind,左节点为2ind,右节点为2ind+1,。用递归的思想,记录下最大的下标数,如果和总结点数一样多,那么就是完全的了。
着重要注意这里的递归出口为当前结点为叶子时退出

if(root->lchild==NULL&&root->rchild==NULL){
	记录最大下标
}

ac代码:

#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
struct node{
	int data;
	int height;
	node* lchild;
	node* rchild;
};
int getHeight(node* root){
	if(root==NULL)return 0;
	return root->height;
}
void updateHeight(node* root){
	root->height = max(getHeight(root->lchild),getHeight(root->rchild))+1;
}
int getBF(node* root){
	return getHeight(root->lchild)-getHeight(root->rchild);
}
void L(node* &root){
	node* temp = root->rchild;
	root->rchild = temp->lchild;
	temp->lchild = root;
	updateHeight(root);
	updateHeight(temp);
	root = temp;
}
void R(node* &root){
	node* temp = root->lchild;
	root->lchild = temp->rchild;
	temp->rchild = root;
	updateHeight(root);
	updateHeight(temp);
	root = temp;
}
void insert(node* &root,int data){
	if(root==NULL){
		root = new node;
		root->data = data;
		root->height = 1;
		root->lchild = root->rchild = NULL;
	}else{
		if(data<root->data){
			insert(root->lchild,data);
			updateHeight(root);
			if(getBF(root)==2){
				int f = getBF(root->lchild);
				if(f==1){//LL
					R(root);
				}else if(f==-1){//LR
					L(root->lchild);
					R(root);
				}
			}
		}else{
			insert(root->rchild,data);
			updateHeight(root);
			if(getBF(root)==-2){
				int f = getBF(root->rchild);
				if(f==-1){//RR
					L(root);
				}else if(f==1){//RL
					R(root->rchild);
					L(root);
				}
			}
		}
	}
}
node* Create(int a[],int n){
	node* root = NULL;
	for(int i=0;i<n;i++){
		insert(root,a[i]);
	}
	return root;
}
void levelOrder(node* root){
	queue<node*> q;
	vector<int> v;
	q.push(root);
	while(!q.empty()){
		node* temp = q.front();
		v.push_back(temp->data);
		if(temp->lchild!=NULL)q.push(temp->lchild);
		if(temp->rchild!=NULL)q.push(temp->rchild);
		q.pop();
	}
	for(int i=0;i<v.size();i++){
		if(i!=0)
			printf(" ");
		printf("%d",v[i]);
	}
}
int MAX = -1;
void func(node* root,int ind){
	if(root->lchild==NULL&&root->rchild==NULL){
		if(MAX<ind)
			MAX = ind;
	}else{
		if(root->lchild!=NULL)func(root->lchild,2*ind);
		if(root->rchild!=NULL)func(root->rchild,2*ind+1);
	}
}
int main(){
	int n;
	int a[100];
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
	}
	node* root = Create(a,n);
	levelOrder(root);
	func(root,1);
	if(MAX!=n)
		printf("\nNO\n");
	else
		printf("\nYES\n");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值