NTA算法讲解

来源:互联网 发布:百事通软件下载 编辑:程序博客网 时间:2024/06/05 19:59

注:

问题描述:

       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 22 11 02 20 2 1 03 22 22 31 21 22 13 2                            //发射表按行输入3          //树的深度(即行数-1)ab ca b c bb 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; }




0 0
原创粉丝点击