1.二叉树的编号
1.1 UVA679 小球下落 Dropping Balls
#include <cstdio>
#include <iostream>
using namespace std;
//快读
inline int read() {
int x = 0;
char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch -'0', ch = getchar();
return x;
}
int main() {
int T = read();
while (T--) {
int D = read(), I = read(), ans = 1; //ans是小球当前所在的节点
//要下落D-1次
for (int i = 0; i < D - 1; ++i) {
//奇数个就落到左子树上
if (I % 2) ans = ans * 2; //小球是第几个落在当前节点的
//偶数个就落到右子树上
else ans = ans * 2 + 1;
I = (I + 1) / 2;
}
printf("%d\n", ans);
}
return 0;
}
2.二叉树的层次遍历
2.1 UVA122 树的层次遍历 Trees on the level
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+100;
char s[maxn];//保存读入结点
bool failed;
//结点类型
struct Node{
bool have_value;//是否被赋值过
int v;//结点值
Node *left,*right;
Node():have_value(false),left(NULL),right(NULL){}//构造函数
};
Node* root;//二叉树的根结点
Node* newnode(){ return new Node(); }
inline void remove_tree(Node* u){
if(u==NULL) return;//提前判断比较稳妥
remove_tree(u->left);//递归释放左子树的空间
remove_tree(u->right);//递归释放右子树的空间
delete u;//调用u的析构函数并释放u结点本身的内存
}
//用队列实现bfs完成层次顺序遍历这棵树
inline bool bfs(vector<int>& ans){
queue<Node*> q;
ans.clear();
q.push(root);//初始时只有一个根结点
while(!q.empty()){
Node* u=q.front(); q.pop();
if(!u->have_value) return false;//有结点没有被赋值过,表明输入有误
ans.push_back(u->v);//增加到输出序列尾部
if(u->left!=NULL) q.push(u->left);//把左子结点(如果有)放进队列
if(u->right!=NULL) q.push(u->right);//把右子结点(如果有)放进队列
}
return true;//输入正确
}
inline void addnode(int v,char* s){
int n=strlen(s);
Node* u=root; //从根结点开始往下走
for(int i=0;i<n;i++){
if(s[i]=='L'){
if(u->left==NULL) u->left=newnode();//结点不存在,建立新结点
u=u->left;//往左走
}else if(s[i]=='R'){
if(u->right==NULL) u->right=newnode();
u=u->right;//往右走
} //忽略其他情况,即最后那个多余的右括号
}
if(u->have_value) failed=true;//已经赋过值,表明输入有误
u->v=v;
u->have_value=true;//别忘记做标记
}
inline bool read_input(){
failed=false;
remove_tree(root);
root=newnode();//创建根结点
for(;;){
if(scanf("%s",s)!=1) return false;//整个输入结束
if(!strcmp(s,"()")) break;//读到结束标志,退出循环
int v;
sscanf(&s[1],"%d",&v);//读入结点值
addnode(v,strchr(s,',')+1);//查找逗号,然后插入结点
}
return true;
}
vector<int> ans;
int main(){
while(read_input()){
if(failed || !bfs(ans)) {
printf("not complete");
}else {
for(vector<int>::iterator t=ans.begin(); t!=ans.end(); t++) {
if(t != ans.end()-1) {
printf("%d ",*t);
}else {
printf("%d",*t);
}
}
}
printf("\n");
}
return 0;
}
2.2 UVA548 树 Tree
分析:后序遍历的第一个字符就是根,因此只需在中序遍历中找到它,就知道左右子树的中序遍历和后序遍历。这样可以先把二叉树构造出来,然后再执行一次递归遍历,找到最优解。
#include<bits/stdc++.h>
using namespace std;
//因为各个结点的权值各不相同且都是正整数,直接用权值作为结点编号
const int maxv=10000+10;
const int inf=0x7fffffff;
int in_order[maxv],post_order[maxv],lch[maxv],rch[maxv];
int n;
bool read_list(int* a){
string line;
if(!getline(cin,line)) return false;
stringstream ss(line);
n=0;
int x;
while(ss>>x) a[n++]=x;
return n>0;
}
//把in_order[L1..R1]和post_order[L2..R2]建成一棵二叉树返回树根
int build(int L1,int R1,int L2,int R2){
if(L1>R1) return 0;//空树
int root=post_order[R2];
int p=L1;
while(in_order[p]!=root) p++;
int cnt=p-L1;//左子树的结点个数
lch[root]=build(L1,p-1,L2,L2+cnt-1);
rch[root]=build(p+1,R1,L2+cnt,R2-1);
return root;
}
int best,best_sum;//目前为止的最优解和对应的权值和
void dfs(int u,int sum){
sum+=u;
if(!lch[u]&&!rch[u]){//叶子
if(sum<best_sum || (sum==best_sum&&u<best)){
best=u;
best_sum=sum;
}
}
if(lch[u]) dfs(lch[u],sum);
if(rch[u]) dfs(rch[u],sum);
}
int main(){
while(read_list(in_order)){
read_list(post_order);
build(0,n-1,0,n-1);
best_sum=inf;
dfs(post_order[n-1],0);
cout<<best<<"\n";
}
return 0;
}
2.3 UVA839 天平 Not so Mobile
#include<bits/stdc++.h>
using namespace std;
//输入一个子天平,返回天平是否平衡,参数W修改为子天平的总重量。
bool solve(int& W){
int W1,D1,W2,D2;
bool b1=true,b2=true;
cin>>W1>>D1>>W2>>D2;
if(!W1) b1=solve(W1);
if(!W2) b2=solve(W2);
W=W1+W2;
return b1 && b2 && (W1*D1 == W2*D2);
}
int main(){
int T,W;
cin>>T;
while(T--){
if(solve(W)) cout<<"YES\n";
else cout<<"NO\n";
if(T) cout<<"\n";
//两组询问输出之间要空一行,最后一组询问不能多输出空行
}
return 0;
}
2.4 UVA699 下落的树叶 The Falling Leaves
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+100;
int sum[maxn];
//输入并共计一颗子树,树根水平位置为p
void build(int p){
int v; cin>>v;
if(v==-1) return;//空树
sum[p]+=v;
build(p-1);build(p+1);
}
//边读入边统计
bool init(){
int v; cin>>v;
if(v==-1) return false;
memset(sum,0,sizeof(sum));
int pos=maxn/2;//树根的水平位置
sum[pos]=v;
build(pos-1); build(pos+1);
return true;
}
int main(){
int kase=0;
while(init()){
int p=0;
while(sum[p]==0) p++;//找最左边的叶子
cout<<"Case "<<++kase<<":\n"<<sum[p++];//因为要避免行末多余空格
while(sum[p]!=0) cout<<" "<<sum[p++];
cout<<"\n\n";
}
return 0;
}
2.5 UVA297 四分树 Quadtrees
#include <bits/stdc++.h>
using namespace std ;
const int len = 32 ;
const int maxn = 32 * 32 + 10 ;//字符串最大不超过1024
char s[maxn] ;
int buf[len][len] ;
int cnt ;
//把字符串s[p..]导出到以(r,c)为左上角,边长为w的缓冲区中
//2 1
//3 4
void draw(const char* s, int& p, int r, int c, int w){
char ch = s[p] ;
p ++ ;
if (ch == 'p'){//Both black and white
int nxt = w / 2 ;
draw(s, p, r , c + nxt, nxt) ;//1
draw(s, p, r , c , nxt) ;//2
draw(s, p, r + nxt, c , nxt) ;//3
draw(s, p, r + nxt, c + nxt, nxt) ;//4
return ;
}else if (ch == 'f'){//画黑像素(白像素不画)
for (int i = r ;i < r + w ;i ++){
for (int j = c; j < c + w; j ++){
if (buf[i][j]==0){
buf[i][j] = 1 ;
cnt ++ ;
// count the black pixels
}
}
}
}
return ;
}
int main(){
int T ;
scanf("%d", &T) ;
while(T --){
cnt = 0 ;
memset(buf, 0, sizeof(buf)) ;
for (int i = 1 ;i <= 2 ;i ++){
scanf("%s", &s) ;
int p = 0 ;
draw(s, p, 0, 0, len) ;
}
printf("There are %d black pixels.\n", cnt) ;
}
return 0 ;
}