2-10 到底爱不爱我
- 分数:10
- 作者:陈越
- 单位:浙江大学

题目描述
古代少女有了心上人时,会悄悄折一条树枝,揪那枝上的叶子,揪一片叶子念一句“爱我”,再揪一片念一句“不爱我”…… 这样揪落最后一片叶子的时候,看看是停在“爱”还是“不爱”。
但聪明的慧娘一眼洞穿,只要数一下叶子有多少片,根据这个数字的奇偶性判断是以“爱”开始还是以“不爱”开始,就总是可以最后落在“爱”上。这个游戏顿时就变得无趣了 —— 真的是文科生制造浪漫,理科生杀死浪漫。
于是有着工科生大脑的慧娘打算另外制作一个更有趣的浪漫游戏。她用不同植物的枝条做成了三种“情枝”:
- “专情枝”:是一根有两个分岔的树枝,只有当两个分岔上连接的枝条传过来的情话都是“爱”的时候,这根枝条的根部才传出“爱”;否则树枝根部传出的是“不爱”。
- “博爱枝”:也是一根有两个分岔的树枝,只有当两个分岔上连接的枝条传过来的情话都是“不爱”的时候,这根枝条的根部才传出“不爱”;否则树枝根部传出的都是“爱”。
- “情变枝”:是没有分岔的一根直枝,如果一端接到“爱”,另一端必须传出“不爱”;反之如果一端接到“不爱”,另一端则会传出“爱”。
慧娘将这些树枝摆放在院子里,布了一个“情阵”,先选一根特殊的枝条作为初试一枝,从这枝条的根部开始,扩散开去,令它们根枝相连。然后她在末梢的枝杈旁随意写下“爱”或“不爱”。现在请你写个程序帮她算出来,在初始一枝的根部,她能得到“爱”还是“不爱”?
输入格式
- 第一行给出正整数 N(≤30),是慧娘制作的情枝数量。所有情枝从 1 到 N 编号。
- 随后 N 行,第 i 行给出第 i 枝的描述,格式为:
类型 左分枝连接的编号 右分枝连接的编号- 类型为 1 代表专情、2 代表博爱、3 代表情变;
- 情变枝仅含唯一末端连接的情枝编号,无右分枝信息;
- 若一个分枝是末梢(未连接其他枝条),则对应编号为 0。
- 接下来一行给出正整数 K(≤30),是询问次数。
- 以下 K 行,每行给出一个由 0 和 1 组成的字符串:
- 0 表示“不爱”,1 表示“爱”;
- 字符串是慧娘从左到右在每个枝杈末梢处写下的(“从左到右”指从初试一枝出发遍历所有末梢时,先遍历左边情阵、再遍历右边情阵)。
输出格式
对每个询问,若初始一枝的根部能得到“爱”,输出 Ai;否则输出 BuAi。
输入样例
6
2 6 4
1 0 0
3 1
2 0 0
3 0
1 5 2
5
11111
00000
11100
10011
01100
输出样例
BuAi
Ai
Ai
BuAi
BuAi
样例说明
样例对应的情阵以及慧娘第 3 问的情势如图所示,其中完整的心对应 1,裂开的心对应 0。

限制条件
- 代码长度限制:16 KB
- 时间限制:400 ms
- 内存限制:64 MB
- 栈限制:8192 KB
解析
#include<stdio.h>
#include<stdlib.h>
#define N 61
typedef enum{
Devotion = 1, // 专情
Fraternity, // 博爱
Paradox // 情变
}BranchType;
typedef enum{
Error = -1,
No,
Yes
}Answer;
// 定义一棵二叉树(顺序表)
/* ==================================================================*/
typedef struct{
BranchType tag; // 标记枝条类型
int parent; // 父结点编号
int left, right; // 左右孩子编号
}TreeNode;
typedef struct{
TreeNode *nodes; // 结点
int root; // 根结点编号
int count; // 结点数量
}Tree;
// 创建一棵树
Tree *createTree(int size){
if(size <= 0) return NULL;
Tree *tree = malloc(sizeof(Tree)); if(!tree) return NULL;
tree->nodes = malloc(sizeof(TreeNode) * (size + 1));
if(!tree->nodes){
free(tree);
return NULL;
}
for(int i = 1; i <= size; i++){
tree->nodes[i].parent = -1; // 父亲初始化为-1
tree->nodes[i].left = tree->nodes[i].right = 0; // 孩子初始化为0
}
tree->root = -1; // 初始化根
tree->count = size; // 树中结点数
return tree;
}
// 释放一棵树
void releaseTree(Tree *tree){
if(tree){
if(tree->nodes){
free(tree->nodes);
}
tree->count = 0;
free(tree);
}
}
void insertNode(Tree *tree, BranchType tag, int curNode, int left, int right){
if(!tree || tree->count <= 0) return;
if(left < 0 || left > tree->count || right < 0 || right > tree->count) return;
// 给curNode添加孩子
tree->nodes[curNode].tag = tag;
tree->nodes[curNode].left = left;
tree->nodes[curNode].right = right;
// 给孩子添加父亲
if (left)
tree->nodes[left].parent = curNode;
if (right)
tree->nodes[right].parent = curNode;
}
/* ==================================================================*/
// 利用后序遍历求的最终结果
Answer postOrderTraverse(Tree *tree, int cur, char *ask, int *pos){
if(!tree || tree->count <= 0) return Error;
Answer leftAns, rightAns; // 暂存当前结点左右分枝结果
// 先判断当前结点类型,来确定分枝情况,做相应处理
switch (tree->nodes[cur].tag) {
case Devotion: // 专情枝
// 处理左分枝
if (tree->nodes[cur].left == 0) {
// 左分枝为末梢
leftAns = ask[(*pos)++] == '1' ? Yes : No;
}
else {
leftAns = postOrderTraverse(tree, tree->nodes[cur].left, ask, pos); // 左子树结果
}
// 处理右分枝
if (tree->nodes[cur].right == 0) {
// 右分枝为末梢
rightAns = ask[(*pos)++] == '1' ? Yes : No;
}
else {
rightAns = postOrderTraverse(tree, tree->nodes[cur].right, ask, pos); // 右子树结果
}
return leftAns & rightAns; // 都爱才爱
case Fraternity: // 博爱枝
// 处理左分枝
if (tree->nodes[cur].left == 0) {
// 左分枝为末梢
leftAns = ask[(*pos)++] == '1' ? Yes : No;
}
else {
leftAns = postOrderTraverse(tree, tree->nodes[cur].left, ask, pos); // 左子树结果
}
// 处理右分枝
if (tree->nodes[cur].right == 0) {
// 右分枝为末梢
rightAns = ask[(*pos)++] == '1' ? Yes : No;
}
else {
rightAns = postOrderTraverse(tree, tree->nodes[cur].right, ask, pos); // 右子树结果
}
return leftAns | rightAns;
case Paradox: // 情变枝
// 只判断左分枝
if (tree->nodes[cur].left == 0) {
// 左分枝为末梢
leftAns = ask[(*pos)++] == '1' ? Yes : No;
}
else {
leftAns = postOrderTraverse(tree, tree->nodes[cur].left, ask, pos); // 左子树结果
}
return !leftAns;
default:
return Error;
}
}
int main(){
int n; scanf("%d", &n); // n根情枝[1, n]
Tree *tree = createTree(n); // 创建一棵树
BranchType tag;
int left, right; // 暂存左右孩子
// 构建联系
for(int i = 1; i <= n; i++){
scanf("%d", &tag);
left = right = 0;
if(tag == Paradox){
scanf("%d", &left); // 情变枝只读一个
}
else{
scanf("%d %d", &left, &right); // 另外两种情枝读两个
}
insertNode(tree, tag, i, left, right); // 插入结点
}
// 找到根
for(int i = 1; i <= n; i++){
if(tree->nodes[i].parent == -1){
tree->root = i;
break;
}
}
int k; scanf("%d", &k); // k次询问
char ask[N]; // 询问
for(int i = 0; i < k; i++){
scanf("%s", ask);
int pos = 0; // 遍历ask所需指针
Answer ans = postOrderTraverse(tree, tree->root, ask, &pos); // 通过后序遍历得到根部结果
if(ans == No){
printf("BuAi\n");
}
else if(ans == Yes){
printf("Ai\n");
}
}
releaseTree(tree); // 释放一棵树
return 0;
}

被折叠的 条评论
为什么被折叠?



