程序设计——第4月CSP模拟考试(判断是否能构成二叉搜索树)

TT数鸭子&ZJM要抵御宇宙射线

这两道题目比较简单,只需要注意如下几点:
(1)鸭子映射成的数字数位中不同的数字个数最大为10,即这个数字中出现了0、1、2、3、4、5、6、7、8、9。但是题目描述中,给出的k值范围很令人迷惑,所以要相信自己的理解,坚定自己的想法。
(2)给出的时间是5s,而且最多只有1000个点,说明可以暴力枚举。计算出以每个点为圆心算出来的半径,之后选最小值。

宇宙狗的危机

问题描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路分析

小建议:涉及动态规划的题目都比较难,根据时间把握情况,尝试暴力求解前几个点,可能会得一些分数。暴力求解:对每个节点进行枚举,检查以该点为根是否可以构成二叉搜索树。

动态规划思路:首先定义二维数组f1,f2,le,ri,f1[i][j]=1表示第i个节点到第j个节点可以构成二叉搜索树,f2[i][j]=1表示第i个和第j个节点的公约数大于1,le[i][root]=1表示以root为根,向左到第i个节点作为root的左子树,形成合法的二叉搜索树。re[root][j]表示以root为根,向右到第j个节点构成其右子树,形成合法的二叉搜索树。
状态转移方程:
if(le[j][root]&&ri[root][k])
{
f1[j][k]=1;//标记F1
if(f2[j-1][root]) ri[j-1][k]=1;
if(f2[root][k+1]) le[j][k+1]=1;
}
当le[j][root]&&ri[root][k]为真时,说明保证了从j到k能构成根为root的二叉搜索树,则令f1[j][jk]=1。如果f2[j-1][root]=1,说明第j-1个节点可以连接到以root为根的二叉搜索树的左子树中,那么说明第j-1到第k个节点可以构成root的左子树;f2[root][k+1]=1分析同理。

代码实现

#include<cstdio>
#include<algorithm>
#include<cstring> 
using namespace std;
const int maxn=750;

int T,n,a[maxn];
int f1[maxn][maxn],f2[maxn][maxn],le[maxn][maxn],ri[maxn][maxn];
//f1[i][j]i到j是否能构造二叉搜索树
//le[i][j]表示以j为根,向左到i可以作为i的左子树
//ri[i][j]表示以i为根,向右到j作为i的右子树 
int gcd(int x,int y){
	return y==0?x:gcd(y,x%y);
}

int main(){
	scanf("%d",&T);
	while(T--){
		memset(f1,0,sizeof(f1));memset(f2,0,sizeof(f2));
		memset(le,0,sizeof(le));memset(ri,0,sizeof(ri));
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			le[i][i]=1;ri[i][i]=1;
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				if(gcd(a[i],a[j])>1&&i!=j) f2[i][j]=1;
				//记录任意树边满足公约数超过1的 
			}
		}
		for(int i=0;i<n;i++){
			for(int j=1;i+j<=n;j++){
				int k=i+j;
				for(int root=j;root<=k;root++){
					if(le[j][root]&&ri[root][k]){//如果左子树和右子树都是合法的二叉搜索树 
						f1[j][k]=1;
						if(f2[j-1][root]) ri[j-1][k]=1;
						if(f2[root][k+1]) le[j][k+1]=1;
					}
				}
			}
		}
		if(f1[1][n]) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值