绘制一颗折半查找判定树

这篇博客介绍了一种使用C++实现的绘制向上取整和向下取整判定树的方法,遵循王道所讲的规律。代码示例展示了如何通过递归函数`draw`来构建和遍历判定树,并通过`dfs`进行深度优先搜索。同时,文章还提供了输出判定树到终端的辅助函数,用于展示树的结构。内容涉及编译器设置、二叉树的构建和遍历,适合C++初学者和算法学习者。
摘要由CSDN通过智能技术生成

编译器: std=c++14 or higher;环境:Mac OS X (M1 Core);
通过define UPPERBOUND和LOWERBOUND可以绘制向上取整、向下取整的判定树。
和王道所讲的规律是一致的;
2017的真题,或者用这个性质去做,或者根据判定树的构造方法去做,即,先标好中序遍历的次序,然后去看每次生成的新节点是不是都遵循相同的生成规则。
Lowerbound的例子

#include <iostream>
#include <vector>
using namespace std;
#define UPPERBOUND
const int N = 1005;

int lchild[N], rchild[N];

int draw(int l, int r) {
	if (l > r) return -1;
	if (l == r) return l;
	#ifdef UPPERBOUND
	int mid = (l + r + 1) >> 1;
	#endif

	#ifdef LOWERBOUND
	int mid = (l + r) >> 1;
	#endif
	int L = draw(l, mid - 1), R = draw(mid + 1, r);
	if (L != -1)
		lchild[mid + 1] = L + 1;
	if (R != -1)
		rchild[mid + 1] = R + 1;
	//printf("%d, %d, %d\n", L + 1, mid + 1, R + 1);
	return mid;
}

vector<pair<int, int>> ret;

int dfs(int u, int depth, int ind) {
	int p = 0;
	if (lchild[u]) {
		p = max(p, dfs(lchild[u], depth + 1, ind * 2 - 1));
	} else {
		ret.push_back({depth + 1, ind * 2 - 1});
	}
	if (rchild[u]) {
		p = max(p, dfs(rchild[u], depth + 1, ind * 2));
	} else {
		ret.push_back({depth + 1, ind * 2});
	}
	//cout << u << ' ' << p << endl;
	return p + 1;
}

typedef short unsigned int hu;
enum { M = 10 };

//中间这一段输出是抄的洛谷输出二叉树的题解

int k,n,m,p,x,y;
char c[800][1600];
bool f[800][1600];//在第x,y点,a,b是用来判节点的,k表示点还是边,xx,yy表示这个点或这个边的父亲

void dfs1(int x,int y,int a,int b,int k,int xx,int yy){
    if(x==n){c[x][y]='o';return;}
    if(k==1){
        c[x][y]='o';
        int X=xx+1,Y=(yy-1)*2+1;//左儿子
        if(!f[X][Y])dfs1(x+1,y-1,a+1,b,2,X,Y);
        X=xx+1,Y=yy*2;//又儿子
        if(!f[X][Y])dfs1(x+1,y+1,a+1,b,3,X,Y);
    }else
    if(k==2){
        c[x][y]='/';
        if(a*2==b)dfs1(x+1,y-1,1,a,1,xx,yy);//这个就是判断接下来是边还是点
        else    dfs1(x+1,y-1,a+1,b,2,xx,yy);
    }else
    if(k==3){
        c[x][y]=92;
        if(a*2==b)dfs1(x+1,y+1,1,a,1,xx,yy);
        else    dfs1(x+1,y+1,a+1,b,3,xx,yy);
    }
}
void make(int k){
    n=3;
    for(int i=3;i<=k;i++)n*=2;
    m=6*(1<<(k-2))-1;//计算画布大小
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)c[i][j]=' ';//填充画布
    dfs1(1,m/2+1,1,n,1,1,1);
}

void toTerminal(vector<pair<int, int>> got) {
	memset(f, 0, sizeof f);
	memset(c, 0, sizeof c);
	for (int i = 0; i < p; i ++) {
		int x = got[i].first, y = got[i].second;
		f[x][y] = 1;
	}
	if(k==1)n=m=1,c[1][1]='o';else make(k);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++)cout<<c[i][j];cout<<endl;
    }
}

int main() {
	for (int i = 1; i < 50; i ++) {
		memset(lchild, 0, sizeof lchild);
		memset(rchild, 0, sizeof rchild);
		int root = draw(0, i - 1) + 1;
		ret.clear();
		int depth = dfs(root, 1, 1);
		int ans = 0;
		for (auto [a, b]: ret) {
			if (a <= depth)
				ans ++;
		}
		k = depth, p = ans;
		vector<pair<int, int>> gotcha;
		for (auto [a, b]: ret) {
			if (a > depth)
				continue;
			gotcha.push_back({a, b});
		}
		printf("Case %d:: \n", i);
		toTerminal(gotcha);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值