ZOJ 1011

来源:互联网 发布:淘宝主图点击率怎么看 编辑:程序博客网 时间:2024/06/07 03:31

ZOJ 1011 - NTA 英文题目
《算法分析与设计-以大学生程序设计竞赛为例》

算法分析


1. 样例分析

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

2. 信号发射表的数据结构

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

// 定义信号的结构体struct signal {    int left, right;};// 使用vector容器定义信号发射表vector<signal>table[20][20];// push_back()方法存集合元素signal pair;    // 定义signal的变量scanf("%d%d", &pair.left, &pair.right);table[i][j].push_back(pair);  // 构造集合

3. 信号数据的读取方法

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

// ---- 算法1 读取数据,构造信号发射表void readTable() {    char ch;    for(int i=0; i<n; i++) {        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') break;                    // 判断回车        }    }}

4. 完全二叉树的数据结构

  从根结点开始对树的结点按深度优先原则进行编号,根据结点编号node。
  int left = node*2 + 1;
  int right = left + 1;
  使用一维数组存储了一颗完全二叉树:
  char tree[1000];
  树的构造在函数void readTree()中完成。其中treeDeep表示结点编号,从0到9,每读取一个结点,编号加1。当树构造完毕,treeDeep中存放了树的结点总数。

// ---- 算法2 构造完全二叉树void readTree() {    char ch;    treeDeep = 0;    // 树结点从0开始编号    int i, j;        // i表示树的每一行,j表示数的每一个结点    // treeLevel 是树的深度    for( i=0; i<=treeLevel; i++ ) { // 树的每一行        for( j=0; j<(1<<i); j++ ) { // 该行中树的每一个结点            cin >> ch;              // 自动跳过空格            tree[treeDeep] = ch;    // 形成树的结点            treeDeep++;             // 产生下一个结点编号        }    }}

5. 合法性判断

  一颗完全二叉树的遍历与搜索,可以使用回溯算法。
  在函数 bool judge( int signal, int node)中,signal表示传入该结点node的信号。
  对结点node,要检查是不是为空“*”,或者超出总结点数 treeDeep。
  (1)如果结点编号node>= treeDeep,表示其父结点是叶子结点,这时需要判断信号是不是合法的。如果是合法的,表示父结点产生的一对信号中,传过来的这个信号是合法的。
  (2)对该结点的所有信号发射单元产生的信号逐一进行检查,如果所有的信号使其所到的叶子结点产生的信号都是非法的,则该树就是非法的。

// ---- 算法3 树的合法性判断// 形参signal表示该结点node的信号bool judge(int signal, int node) {    int signal1, signal2;    //     if( tree[node]=='*' || node>=treeDeep ) {        //        if( signal<n-m ) return false;        else return true;    }    // 结点的信号发射单元编号    int k1 = tree[node]-'a';    // 该结点的左子树编号    int left = node*2 + 1;    // 该结点的右子树编号    int right = left + 1;    // table[signal][k1].size()是信号发射表中,该结点链表的长度    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, left) && judge(signal2, right) ) return true;    }    return false;}

英文积累


ZOJ 1011 - NTA 英文题目

acceptable signals  合法信号
auxiliary       n.辅助
non-leaf node    非叶子结点
finite        adj.有限的
signal-transmitting  信号发射
substance      n.介质
non-deterministically    非确定性,随机
successor      n.继承者(这里为子树)
for simplicity     简单起见
consecutive     adj.连续的
configuration     n.结构

代码实现


/** 题目来源:浙大ZOJ,编号1011,题名"NTA" URL:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1011 Author:Christina Finish Time:2017.09.26*/ #include #include using namespace std; struct signal                    // 信号  {       int left,right;              // 左右子树  };     vector 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> 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
原创粉丝点击