ZOJ 1011 - NTA

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
      
      
     
     
    
    
   
   
  
  


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值