洛谷OJ P1087 FBI树

题目:

题目描述
我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。

FBI树是一种二叉树,它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2^N
的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:

  1. T的根结点为R,其类型与串S的类型相同;

  2. 若串S的长度大于1,将串S从中间分开,分为等长的左右子串S1
    ​ 和S_2
    ​ ;由左子串S_1
    ​ 构造R的左子树T_1
    ​ ,由右子串S_2
    ​ 构造R的右子树T_2
    ​ 。

现在给定一个长度为2^N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历序列。

输入输出格式
输入格式:
第一行是一个整数N(0≤N≤10),

第二行是一个长度为2^N
的“01”串。

输出格式:
一个字符串,即FBI树的后序遍历序列。


自己的分析:最简单的思路:就直接按照题意模拟,建一颗树,然后对这个树进行后序遍历。

卡的最久的点就是建树的过程了,自己打的方法是:每次建立左(右)子树前传递父节点的左(右)指针。在递归中,每次判断完当前节点的字母后,用引用把传进来的父节点左(右)指针指向当前节点。其他都好办,就是根节点要特别处理,因为它的特征与其他节点相同,但却不用“把父节点指向自身”。所以我人为得加了一个参数sign来区分根节点和非根节点,只有第一次执行建树函数时sign才为1,其他都传入0。

贴上自己的代码:

#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
using namespace std;
typedef struct tnode* link;
typedef struct tnode {
	char ch;
	link left;
	link right;
	int sign;
}node;
char str[1025];
int judge(int left, int right) {                 //判断一个节点的字符串对应的字母
	bool one = false;
	bool zero = false;

	for (int i = left; i!= right + 1; i++) {
		if (str[i] == '0')   zero = true;
		else if (str[i] == '1') one = true;
	}
	if (zero == true && one == true)   return 1;
	else if (zero == true && one == false) return 2;
	else if (zero == false && one == true)    return 3;
}
link create(int left, int right,link& father,int sign) {       //通过递归来建树
	int length = (right - left + 1);
	int type = judge(left, right);

	link p = new node();
	if (type == 1)  p->ch = 'F';
	else if (type == 2) p->ch = 'B';
	else if (type == 3) p->ch = 'I';
;

	if (length > 1) {
		if (sign==1) {        //sign为人为添加的标记,说明这个节点是根节点
			create(left, (left+right)/2, p->left,0);
			create((left+right)/2+1, right, p->right,0);
		}
		else {                        //不是根节点的话先与父节点连接
			father = p;
			create(left, (left + right) / 2, p->left,0);
			create((left + right) / 2 + 1, right, p->right,0);
		}
	}
	else {
		p->left = NULL;
		p->right = NULL;
		father=p;
	}
	return p;
}

void postorder(link p) {
	if (p) {
		postorder(p->left);
		postorder(p->right);
		cout << p->ch;
	}
}

int main() {
	int n,i,length;
	bool one = false;
	bool zero =false;
	link root=NULL;

	cin >> n ;
	length = pow(2, n);

	for (i = 1; i <= length; i++) {
		cin >> str[i] ;
	}

	root = create(1,length,root,1);
	postorder(root);
}



反思、收获:

1.把字符串二分的过程中的左右子区间的下标自己还不熟悉:

(对于int值(下标),左下标为left,右下标为right):

区间从0、1开始都通用:左子区间为(left,(left+right)/2) , 右子区间为((left+right)/2+1,right ).
(其中,区间中有偶数个元素时左右子区间相等大小,为奇数时左子区间比右子区间长度多1)

2原来与树的遍历有关的题目还可以直接输出每步结果,并不实际建树。学到了

洛谷(Luogu)是一个非常受欢迎的在线算法题库网站,它包含了各种计算机科学题目,包括数据结构、算法等。P1862输油管道问题是关于动态规划的一种典型应用,通常涉及到计算最短路径或者最优解。 在这个特定的问题中,输油管道网络可能会包含节点(代表城市)和连接它们的管道,每个管道有容量和成本。目标可能是找到从起点到终点的成本最低的输油路线,使得总成本不超过给定的最大费用,并确保满足每条管道的最大通过量。 以下是解决这个问题的一个基本的C++代码框架,采用深度优先搜索(DFS)或广度优先搜索(BFS),结合贪心策略: ```cpp #include <vector> using namespace std; struct Edge { int to, cap, cost; }; class Solution { public: vector<pair<int, int>> dijkstra(vector<Edge>& edges, int s, int t) { // 初始化距离数组和前驱指针 vector<int> dist(n, INT_MAX); vector<int> prev(n, -1); dist[s] = 0; priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; pq.push({0, s}); while (!pq.empty()) { pair<int, int> cur = pq.top(); pq.pop(); int u = cur.second; if (dist[u] != cur.first) continue; // 已经是最小距离,跳过 for (auto& edge : edges[u]) { int v = edge.to; int new_cost = cur.first + edge.cost; if (edge.cap > 0 && new_cost < dist[v]) { dist[v] = new_cost; prev[v] = u; pq.push({new_cost, v}); } } } return prev; } private: int n; // 节点数 }; ``` 请注意,这只是一个简化的模板,实际代码需要处理细节如边界条件、数据有效性检查以及最终的输出部分。如果你想要完整的代码,可以在洛谷官网查看该题目的具体描述和样例输入输出,或者在网上找一些详细的教程和博客文章作为参考。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值