ZOJ-1011-NTA

从根结点开始是信号0,信号发射单元是a,查表该结点产生信号(1,2),信号1给左,信号2给右,标注在结点的连线上,左子树的发射单元是b,可以产生两种信号:(0,2),(1,0)。程序会将这两种信号都向下遍历一遍,最后取信号(1,0)。重复该过程至所有结点。最后我们看到,所有叶子结点产生的信号,都是合法信号,即都是信号2和3,因此该树是有效的,输出单词 valid。

从样例看出,该表不是一个普通的二维表,表中元素的个数是不固定的。很容易想到的办法是建立一个二维数组,其中的元素是链表。这种数据结构是有效的,但使用起来肯定是麻烦的。
使用C++标准模板库的vector容器,可有效地解决数据存储问题。

读取信号数据很麻烦,因为不知道一行到底有多少数据。
  可以把一行数据当作一个字符串,读取一行,然后再从字符串中读取数据,处理的工作量还是比较大的。实际上可以直接判断回车符,以判定当前行是否结束

#include <stdio.h>
#include <vector>
#include <iostream>
using namespace std;

struct Signal{
	int left, right;
};


vector<Signal> table[20][20];
int n, m, k;
int treeLevel;
char tree[2100];
int treeNodeNum;

//读取数据,构造信号发射表 
void readTable(){
	for(int i = 0; i < n; i++){
		for(int j = 0; j < k; j++){
			Signal pairs;
			table[i][j].clear();
			while(1){
				scanf("%d%d", &pairs.left, &pairs.right);
				table[i][j].push_back(pairs);
				char ch = getchar();
				if(ch == '\n') break; 
			}
		}		
	}
}

void readTree(){
	char ch;
	treeNodeNum = 0;//树结点编号, treeLevel为树的深度 
	int i, j;
	for(i = 0; i <= treeLevel; i++){
		for(j = 0; j < (1 << i); j++){
			//scanf("%c", &ch); 
			cin >> ch;
			tree[treeNodeNum] = ch;
			treeNodeNum++;
		}
	}
}

//signal表示该结点node的信号 
bool judge(int signal, int nodeNum){
	int signal1, signal2;
	if(tree[nodeNum] == '*' || nodeNum >= treeNodeNum){
		if(signal < n - m) return false;
		else return true;
	}
	
	int k1 = tree[nodeNum] - 'a';//结点的信号发射单元编号
	int leftNum = nodeNum*2 + 1;//该结点的左子树编号
	int rightNum = leftNum + 1; //该结点的右子树编号 
	for(int i = 0; i < table[signal][k1].size(); i++){
		signal1 = table[signal][k1][i].left;
		signal2 = table[signal][k1][i].right;
		if(judge(signal1, leftNum) && judge(signal2, rightNum)) return true;
	} 
	return false;
}

int main(){
	int icase = 0;
	while(scanf("%d%d%d", &n, &m, &k) && (n || m || k)){
		if(icase++) printf("\n");
		printf("NTA%d:\n", icase);
		readTable();
		while(scanf("%d", &treeLevel) && ( treeLevel != -1)){
			readTree();
			if(judge(0, 0)) printf("Valid\n");
			else printf("Invalid\n");
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值