Best Coder Round#25 1003 树的非递归访问

虽然官方解释是这题目里的树看作无向无环图,从答案来看还是在“以1作为根节点”这一前提下进行的,这棵树搭建好以后,从叶节点开始访问,一直推到根节点即可——很像动态规划的“自底向上”。

但这棵树的搭建堪忧:给出的边不知道哪边更接近根节点。所以我给出的方案干脆在两个顶点都将对方加成孩子,等到访问的时候再作处理,根据从1这个根节点开始访问这个特性,额外加一个“isVisited"来做区分。

然后利用栈对树进行非递归访问

/**
 * For best-coder problem 3
 */
#include <iostream>
using namespace std;

#include <set>
#include <stack>

struct Node
{
public:
    Node() :mIsVisited(false) {}

    bool mIsVisited;
    set< int > mChilds;
    set< int > mColorSet;
};

int main()
{
    int nNode, nCounting;
    while( cin >> nNode >> nCounting )
    {
        Node node[50001];

        int edge[50001][2];
        for( int i=1; i<nNode; i++ )
        {
            int a, b;
            cin >> a >> b;
            node[a].mChilds.insert(b);
            node[b].mChilds.insert(a);
        }

        for( int i=0; i<nCounting; i++ )
        {
            int n, color;
            cin >> n >> color;
            node[n].mColorSet.insert(color);
        }

        stack<int> nodeStack;

        node[1].mIsVisited = true;
        nodeStack.push(1);

        do{
           int currentTop = nodeStack.top();
           Node& topNode = node[currentTop];

           set<int> & topChilds = topNode.mChilds;
           set<int> & topColors = topNode.mColorSet;

           for( set<int>::iterator ci = topChilds.begin();
                ci != topChilds.end();
                ci++ )
           {
               int child = *ci;
               if( node[child].mIsVisited )
               {
                   topChilds.erase(child);
                   continue;
               }

               node[child].mIsVisited = true;
               nodeStack.push(child);
               break;
           }

           // it‘s a leaf child
           if( topChilds.empty() )
           {
               nodeStack.pop();

               if( nodeStack.empty() ) continue;

               Node& topNode = node[ nodeStack.top() ];
               topNode.mColorSet.insert(topColors.begin(),topColors.end());
               topNode.mChilds.erase(currentTop);
               continue;
           }
        }while(!nodeStack.empty());

        // output
        for( int i=1; i<=nNode; i++ )
        {
            cout << node[i].mColorSet.size();
            if( i != nNode )
            {
                cout << " ";
            }else{
                cout << endl;
            }
        }
    }
}

  

时间: 2024-12-20 18:24:38

Best Coder Round#25 1003 树的非递归访问的相关文章

树的非递归遍历——前序、中序、后序

树的递归遍历非常简单,也是写树的遍历时最常用的写法.但是我发现自己对树的非递归遍历并不十分熟悉,所以把三种非递归遍历都写了一遍,以后看到这篇记录博客也可以帮助自己好好回想熟悉一下. Leetcode对应习题:前序,中序,后序. 相对而言,这三种非递归遍历的难度--前序 < 中序 < 后序. 对于第三种(非递归后序遍历)方法,只要稍微调整下第18~19行三个节点push的顺序,就可以实现前中后序的遍历. 树的非递归前序: 1 class Solution { 2 public: 3 vector

二叉树非递归访问

二叉树非递归访问,借助一个栈,来模拟递归调用过程. ? 1 2 3 4 5 6 struct TreeNode {      char val;      TreeNode *left;      TreeNode *right;      TreeNode(int x) : val(x), left(NULL), right(NULL) {}  }; 1. 先序遍历 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void

JumpNode递归和非递归访问

JumpNode的定义结构为如下所示: struct JumpNode { int data; //存储数据 int order; // 记录访问次序,初始化均为0 JumpNode *jump, *next; // next为线性下一节点,jump为跳跃到下一节点 JumpNode(int d): data(d), order(-1), jump(NULL), next(NULL) {} }; 现在需要以递归和非递归的方式来访问到一个JumpNode *list.在访问的时候给各个节点的ord

树的非递归遍历

树是递归定义的,利用递归算法遍历树实现起来比较简单,然而难的是非递归遍历.非递归遍历需要借助栈这一数据结构来完成. 首先定义树的结点和构建链表栈: //定义树的节点 typedef struct Node { int data; struct Node* lchild; struct Node* rchild; }Node; //定义栈节点 typedef struct Stacknode { Node* tnode; struct Stacknode* next; }Stacknode;  /

树的非递归遍历(中序遍历)

中序 遍历的几种情况 分析1:什么时候访问根.什么时候访问左子树.什么访问右子树 当左子树为空或者左子树已经访问完毕以后,再访问根 访问完毕根以后,再访问右子树. 分析2:非递归遍历树,访问结点时,为什么是栈,而不是其他模型(比如说是队列). 先走到的后访问.后走到的先访问,显然是栈结构 分析3:结点所有路径情况 步骤1: 如果结点有左子树,该结点入栈: 如果结点没有左子树,访问该结点: 步骤2: 如果结点有右子树,重复步骤1: 如果结点没有右子树(结点访问完毕),根据栈顶指示回退,访问栈顶元素

[BestCoder Round #25 1003]Harry and Christmas tree

Harry and Christmas tree Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 70    Accepted Submission(s): 3 问题描述 圣诞节的夜晚,哈利得到一棵圣诞树.这棵树由n个节点组成,以1号节点为根.树上的每个节点有一些不同颜色的礼物,于是哈利开始统计树上的礼物.哈利每次统计一个礼物,会记录一

Best Coder Round#25 1001 依赖检测

原题大致上就是检测一系列进程之间是否存在循环依赖的问题,形如: a->b->c->a,  a->a ,都行成了循环依赖,事实上可以视为“检测链表中是否存在环” AC代码: #include <iostream> #include <set> #include <cstring> using namespace std; int main() { int procs[10000]; int nProc, nDep; while( cin >&

树的非递归遍历:一种很好的算法

栈模拟非递归算法 递归算法的本质是利用函数的调用栈进行,实际上我们可以自行使用栈来进行模拟,这样的算法空间复杂度为O(h),h为二叉树的高度. 前序遍历 首先把根节点入栈,然后在每次循环中执行以下操作: 此时栈顶元素即为当前的根节点,弹出并打印当前的根节点. 把当前根节点的右儿子和左儿子分别入栈(注意是右儿子先入栈左儿子后入栈,这样的话下次出栈的元素才是左儿子,这样才符合前序遍历的顺序要求:根节点->左儿子->右儿子). 后序遍历 因为后序遍历的顺序是:左子树->右子树->根节点,

树的遍历(非递归)

描述 树的非递归遍历主要是利用栈来模拟递归的实现,跟递归一样,空间复杂度为O(h=lg(n)) (),时间复杂度为O(n)(每个节点都被压入栈一次,弹出栈一次,访问一次) 前序遍历 前序是先访问,再入栈 void PreorderTraverse(pTree T) { if(T == NULL) return; stack<pTree> Stk; Stk.push(T); while(!Stk.empty()) { pTree p = Stk.top(); Stk.pop(); cout &l