P1087 FBI树

题目链接

P1087 FBI树

思路

思路一

首先题目中说明了"01"串的长度是(2^n),也就是说这是一棵满二叉树,也就是可以用(tree[i])来表示根(tree[2*i])来表示左孩子,(tree[2*i+1])来表示右孩子

所以思路就有了直接递归把树的节点弄成"F","B","I".

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<string>
#include<cstring>
using namespace std;
const int maxn=999999999;
const int minn=-999999999;
inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * f;
}
int tree[100010];
char s[10001];
int len;
int build(int l,int r,int num) {
	if(num==2*len) {
		return 0;
	}
	if(l==r) {
		if(s[l]=='0') {
			tree[num]='B';
			return 'B';
		} else {
			tree[num]='I';
			return 'I';
		}
	}
	char ll=build(l,(l+r)/2,2*num),rr=build((l+r)/2+1,r,2*num+1);
	if(ll=='F'||rr=='F') {
		tree[num]='F';
		return 'F';
	} else {
		if(ll != rr) {
			tree[num]='F';
			return 'F';
		} else {
			if(ll == 'B')	{
				tree[num] = 'B';
				return 'B';
			} else {
				tree[num] = 'I';
				return 'I';
			}
		}
	}
}
void print(int x) {
	if(tree[2*x]) print(2*x);
	if(tree[2*x+1]) print(2*x+1);
	cout<<char(tree[x]);
}
int main() {
	int x=read();
	scanf("%s",s+1);
	len=strlen(s+1);
	build(1,len,1);
	print(1);
	return 0;
}

思路二

仔细观察会发现只要先递归左边在递归右边最后输出就是树的后序遍历,然后就直接计算字串里的(01)数量就行了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<string>
#include<cstring>
#define ll long long int
using namespace std;
const int maxn=999999999;
const int minn=-999999999;
inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * f;
}
int a[10001];
int n;
char s[382479];
void dfs(int l,int r) {
	if(l<r) {
		int mid=(r-l)/2;
		dfs(l,l+mid);
		dfs(l+mid+1,r);
	}
	int sum0=0;
	int sum1=0;
	for(int i=l; i<=r; ++i) {
		if(a[i]==0) sum0++;
		else sum1++;
	}
	if(!sum1) cout<<'B';
	else if(!sum0) cout<<'I';
	else  cout<<'F';
}
int main() {
	cin>>n;
	scanf("%s",s+1);
	int len=strlen(s+1);
	for(int i=1; i<=len; ++i) {
		a[i]=s[i]-'0';
	}
	dfs(1,len);
	return 0;
}

优化

利用前缀和来优化计算01的数量的循环
如果全是(0)(f[r]-f[l-1])相减为(0);
如果全是(1)(f[r]-f[l-1])相减是(r-l+1);
反之是(0,1)都有



#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<string>
#include<cstring>
#define ll long long int
using namespace std;
const int maxn=999999999;
const int minn=-999999999;
inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * f;
}
int n;
char s[382479];
int f[1000101];
void dfs(int l,int r) {
	if (l!=r) {
		int mid=(l+r)/2;
		dfs(l,mid);
		dfs(mid+1,r);
	}
	if(f[r]-f[l-1]==r-l+1) {
		cout<<'I';
	} else if(f[r]-f[l-1]==0) {
		cout<<"B";
	} else cout<<"F";
}
int main() {
	cin>>n;
	scanf("%s",s);
	n=(1<<n);
	for(int i=1; i<=n; i++)
		f[i]=f[i-1]+s[i-1]-'0';
	dfs(1,n);
	return 0;
}

原文地址:https://www.cnblogs.com/pyyyyyy/p/11095551.html