NTA算法讲解

注:

问题描述:

       NTA(Non-deterministic Tree Automata)是一种有多棵树组成的装置。这个装置有一套操作规则。根据这些规则产生一些信号,就形成了一些信号系统。在这个系统里,有一个信号是起始信号,有些信号是合法的,其余的都是辅助信号。若一对信号中两个都是合法的,则有它们组成的一堆信号就是合法的。
      在此只讨论完全二叉树,它的每个非叶子节点都有两棵里,每个节点都有一个信号发射单元。当信号传入节点时,与信号发射单元相遇,激发信号反应,发射单元产生多对信号。然后装置随机选择一组信号发送给子树节点,第一个送给左子树,第二个送给右子树。
NTA的整个操作流程如下:
      装置首先发送起始信号到根节点。由根节点信号发射介质产生多对信号,随即产选择一对信号,将第一个信号发送给左子树,第二个信号发送给右子树,在每个节点都重复这个过程,直到叶子节点。
      若信号达到了一个叶子节点,并且该叶子节点也产生一对合法,则该叶子节点是“可颤动的”.如果搜游叶子节点都是这样,就说这棵树是有效的。 若所有的发射信号都是无效,则这棵树是无效的。
                                                                 样例数据的信号发射表

               T               

                        a                          

b

c

0

(1,2)

(2,1)

(1,0)

1

(2,2)

(0,2),(1,0)

(3,2)

2

(2,2)

(2,3)

(1,2)

3

(1,2)

                           (2,1)                           

              (3,2)              

输入样例:
4 2 3     //4是信号的个数(用0,1,2,3),2是有效信号的个数(即2,3),3是发射单元个数(a,b,c)
1 2
2 1
1 0
2 2
0 2 1 0
3 2
2 2
2 3
1 2
1 2
2 1
3 2                            //发射表按行输入
3          //树的深度(即行数-1)
a
b c
a b c b
b a b a c a * *




(第二个图叶子节点信号有不合法信号所以该树是无效树,第一个树是有效树)
从根节点开始信号是0,信号发射单元是a,查表得该节点产生的信号(1,2),信号1给左子树,信号2给右子树,标注在节点的连线上。左子树的发射单元是b,可以产生两种信号:(0,2)、(1,0)。
具体实现代码:
#include<iostream> 
#include<vector> 
using namespace std; 

struct signal						//信号
{ 
	int left,right;					//左右子树
}; 

vector<signal> table[20][20];		//信号发射表

int n,m,k;							//n是信号的个数,m是和发信号的个数,k是信号发射单元个数
int treeLevel;					    //树的行数
char tree[1000];					//定义一个完全二叉树
int treeDeep;						//树节点编号



/*
*信号数据读取的方法
*   可以把一行数据当作一个字符,读取一行,然后再从字符串中读取数据,
*   处理的工作量还是比较大的。实际上可以直接判断回车符,以判断当前行是否结束
*/
void readTable() 
{ 
	char ch; 
	for(int i=0;i<n;i++) 
		for(int j=0;j<k;j++) 
		{ 
			table[i][j].clear();						//清空该元素
			while (true) {
				signal pair;							//定义signal的变量
				scanf("%d%d",&pair.left, &pair.right);	//读取信号
				table[i][j].push_back(pair);			//构造集合
				ch=getchar();
				if(ch=='\n')							 //判断是否回车,如果ch=' '(空格),则后面还有数据,如果ch='\n'(回车),则没数据
					break;
			}
		} 
} 

//构造完全二叉树
void readTree() 
{ 
	char ch; 
	treeDeep = 0;						//树节点从0开始
	int i,j;
	for(i=0;i<=treeLevel;i++)			//树的每一行
		for(j=0;j<(1<<i);j++)			//该行中树的每个节点
		{ 
			cin>>ch;					//会自动跳过空格
			tree[treeDeep]=ch;			//形成树的一个节点
			treeDeep++;					//产生下一个节点
		} 
} 

/*
*  树的合理性判断
*(1)如果节点编号node>=treeDeep,表示其父类节点是叶子节点,这时需要判断信号是否合法。
*   如果合法,表示父节点产生的一对信号中,传过来的信号是合法的
*(2)对该节点的所有信号发射单元产生的信号逐一进行检查,如果所有的信号时期所有达到的叶子节点产生都是非法的,
*   则该树就是非法的。
*/
bool judge(int signal ,int node)					//signal表示传入该节点node的信号
{ 
	int signal1,signal2; 
	if(tree[node]=='*' || node>=treeDeep)			//叶子节点的合法性判断
		if (signal<n-m)								//后m个信号是合法的
			return false; 
		else 
			return true; 
	int k1 = tree[node]-'a';						//节点的信号发射单元的编号
	int left = node*2+1;							//该节点的左子树编号
	int right = left+1;								//该节点的右子树编号
	for(int i=0; i<table[signal][k1].size(); i++)	//table[signal][k1].size()是信号发射表中,该节点链表的长度
	{ 
		signal1 = table[signal][k1][i].left; 
		signal2 = table[signal][k1][i].right; 
		if(judge(signal1,left) && judge(signal2,right))//signal是传给子节点的信号,left/right是子节点的编号
			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; 
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值