0%

220403总结

被挂在树上的一天(生活在树上.doc

多重背包二进制拆分的时候还写错了个变量

T1 求后序遍历

  • 先序遍历:中 — 左 — 右
  • 中序遍历:左 — 中 — 右
  • 后序遍历:左 — 右 — 中

求后序遍历的基本方法就是,通过先序遍历求出子树的根,再通过中序遍历确定左子树和右子树

没有必要建树

并且由于给出了先序遍历,以 $i$ 为根的子树的根就是先序遍历的第 $i$ 项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//l1,r1为该树在先序遍历中的位置
//l2,r2为该树在中序遍历中的位置

void build(int l1,int r1,int l2,int r2){
int rt = strchr(B,A[l1]) - B;//找子树的根在中序遍历的位置
//左子树长度为rt-l2,右子树长度为r2-rt
// 若 rt-l2 > 0,即 rt > l2 时,有左子树
// 若 r2-rt > 0,即 rt < r2 时,有右子树
//在先序遍历中,
// [l1+1,l1+(rt-l2)]为左子树区间
// [l1+(rt-l2)+1,r2]为右子树区间
//在中序遍历中,[l2,rt-1]即为左子树区间,[rt+1,r2]为右子树区间
//顺便进行后序遍历(左 — 右 — 根)
if(rt > l2) build(l1+1,l1+rt-l2,l2,rt-1);//左
if(rt < r2) build(l1+rt-l2+1,r1,rt+1,r2);//右
printf("%c",A[l1]);//根
}

T2 混合背包

确实是混合背包(指同时出现01背包,多重背包,完全背包)

01背包是个数为1的多重背包

完全背包是个数为正无穷的多重背包

所以三个背包都可以转化为多重背包求解

由于物品的重量为正整数,背包容量上限为200,

所以其实把完全背包看成物品个数为250的多重背包就完全足够了…吧

考虑到没有给出 $w,c,p$ 的数据范围,

对完全背包物品数量进行了二进制拆分

拆分的时候把一个p写成了w丢了60分

再跑一遍01背包即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int V,N;
int dp[100000];
int va[100000];
int we[100000];

scanf("%d%d",&V,&N);

memset(va,0,sizeof(va));
memset(we,0,sizeof(we));

for(int i = 1; i<=N; i++) {
int w,c,p;
scanf("%d%d%d",&w,&c,&p);
if(!p) p = 250;

for(int j = 1;j<=p;j<<=1){
cnt++;
va[cnt] = c * j;
we[cnt] = w * j;
p -= j;
}
if(p){
cnt++;
va[cnt] = c * p;
we[cnt] = w * p;
}
}
for(int i = 1;i<=cnt;i++){
for(int j = V;j>=we[i];j--){
dp[j] = max(dp[j],dp[j-we[i]]+va[i]);
}
}
printf("%d\n",dp[V]);

T3 扩展二叉树

做的时候没考虑到可能只补了一个点的情况

扩展二叉树的序列中一个点要么是补点,要么是树上的点

树上的点的后一个点为其左子树的根,左子树中最后一个点的下一个点为右子树的根

递归求解即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct Tree{
int ls,rs;
char c;
}tree[100000];

char T[100000];
//ind需要放在递归外面,因为它需要不断向后跑
int ind = 0;

void build(){
int rt = ind;
//左子树
if(T[ind+1]!='.'){
tree[rt].ls = ind+1;
ind++;build();
}else{
ind++;
}
//建完左子树,建右子树
if(T[ind+1]!='.'){
tree[rt].rs = ind+1;
ind++;build();
}else{
ind++;
}
}