【问题标题】:Counting univalued subtrees计算单值子树
【发布时间】:2015-09-08 12:59:16
【问题描述】:

在最近的 Codechef 竞赛中,我必须编写一个程序来计算给定树中单值子树的数量。如果子树的所有节点都具有相同的值,则该子树是单值的。

在输入中,节点编号为 0 到 N-1。每个节点都包含一个整数值。每个节点可以有任意数量的边到其他节点。总共有 N-1 条边。树总是以节点 0 为根。

我写了下面的代码:

struct Node {
    int data;
    vector<unsigned> edge; //stores the node number of each child node
};

//i know these really shouldn't be global
unsigned long long count = 0;
vector<Node> tree;

//n is the number of the node at which the tree is rooted
//initally we call isUnivalued(0)
bool isUnivalued(unsigned n) {
    if(tree[n].edge.size() == 0){
        count++;
        return true; //leaves are univalued
    }
    bool allUnivalued = true;
    for(auto i : tree[n].edge)
        if(!isUnivalued(i))
            allUnivalued = false;
    if(!allUnivalued)
        return false;
    for(auto i : tree[n].edge)
        if(tree[i].data != tree[n].data)
            return false;
    count++;
    return true;
}

这为我尝试过的所有小测试用例提供了正确答案。但是当我提交问题时,法官发现某些测试用例的答案不正确。

我正在寻求一些帮助,以了解在什么情况下可能会失败以及为什么会失败。

编辑:示例

  0
 / \
0   1
   / \
  1   1

这里的答案应该是 4。虽然最大的子树(整个树本身)不是单值的,但所有其他子树都是。 假设所有节点的值都是 1,那么答案就是 5。

【问题讨论】:

  • 能不能做个通用的扫地状态验证码?
  • 对不起,我不知道这意味着什么,谷歌搜索也没有帮助。你能详细说明一下吗?
  • 好吧,我会这样做,但是我如何检查返回的答案是否错误,没有用笔和纸计算?
  • 单值树算一还是子树数?
  • 我没有看到任何错误。我能看到的唯一可能出错的情况是,当您的节点数量超过 unsigned int 可以携带的数量时。在向量中,您可以存储 size_t 元素(在大多数平台上都是 unsinged long long)。但是您的边向量只有无符号(int)作为数据类型。因此,如果您的法官确实存储了更多节点,则由于数据截断,某些边缘会出错。

标签: c++ data-structures tree


【解决方案1】:
  • 在进入重点之前,我建议你一个很好的方法来检查你的提交,用长的测试用例而不使用pen&paper

首先,尝试找出一种替代方法来并行执行本机代码,同时比较给定的结果

直到命中条件断点,然后检查它。

其次,在运行两种不同的方法后,结果没有出现这种差异,意味着你的方法的各个方面

只有一个例外,这是一个最终的stack overflow,可能会导致内存过载。

考虑将结构化树作为输入(不过,我不确定应该如何将输入引入系统)

tree[0] , tree[1]  , tree[2]  , tree[3]  ,..., tree[k-1], tree[k]  , tree[k+1],  tree[n]   ,...  
        |          |          |          |...|          |          |          |            |... 
{v1,1,n}|{v2,2,n-1}|{v3,3,n-2}|{v4,4,n-3}|...|{vk,k,k+1}|{vk+1,0,0}|{vk+2,0,0}|{vn+1,n+2,L}|...

tree[k]和tree[k+1]是叶子,栈的结构如下...

v1,v2,V3,V4,...vk,vk+1,-1,vk+2,-1,-1,vk+3,...

这棵树是单线程的,意味着它是线性计算。

举个例子:

级别=0,计数=0。

1      ,1      ,1      ,1      ,-1     ,1      ,-1     ,-1     ,0    (data changed),-1     ,-1     ,1      .
level=0,level=1,level=2,level=3,level--,level=3,level--,level--,reset(level)level=1,level--,level=0,reset(level=1) (data changed)
count=1,count=2,count=3,count=4,count=4,count=5,.......,.......,count=count-level+1,count=4,.......,count=count-0+1=5 (data changed)

树:

            --------1-------        
           -----1----       1   
          --- 1---    0
          1       1        

等级:

            --------0-------        
           -----1----       1   
          --- 2---    1
          3       3        

计数:

            --------1-------        
           -----2----       5   
          --- 3---    4
          4       5        

子树数:5

            --------1-------        
           -----1----       *   
          --- *---    *
          *       *        

-剩下的情况(树的索引混乱且结构错误),这里是如何验证我的,以及你的算法,

看到数值和计时结果:

代码:

#include <algorithm>
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
#include <time.h>
using namespace std;

struct Node {
int data;
int *edge ; //stores the node number of each child node
};
// Yes they are global variables
vector<int> stack;
vector<Node> tree;
vector<int*>callstack;


void fillwithrandom(int *n,int *m,int count)
{
int a;
Node T;
T.data=rand()%2;T.edge=&(*(int*)malloc(3*sizeof(int))=3);
tree.push_back(T);
stack.push_back(T.data);
if ((a=rand()%count)!=0)
   fillwithrandom(&(*n=(T.edge[1]=++(*n))),&(++(*m)),a);
else return stack.push_back((T.edge[0]=0)-++(*m));  


while ((a=rand()%count)==0);
fillwithrandom(&(*n=(T.edge[2]=++(*n))),&(++(*m)),a);

stack.push_back(-++(*m));
}


void iterativetree( int* m){

int level=0,lasti,previouslevel=0,stackk;
callstack.clear();




callstack.push_back(&(*(int*)malloc(2*sizeof(int))=0));stackk=(lasti=tree[callstack[0][1]=0].data);
for (int j=0;j>=0;){


if (stackk>=0)

        if ((lasti&1)==(stackk&1))
          {(*m)++;(level)++;lasti=stackk;}
        else
        {*m=*m-level+1;previouslevel=level;level=1;lasti=stackk;}
else 
(level)-=!!level;


if (++callstack[j][1]==tree[callstack[j][0]].edge[0]|tree[callstack[j][0]].edge[0]==0)
    {callstack.pop_back();j--;stackk=-1;}
    else 
    {callstack.push_back(&(*(int*)malloc(2*sizeof(int))=tree[callstack[j][0]].edge[callstack[j][1]]));
    j++;callstack[j][1]=0;stackk=tree[callstack[j][0]].data;};

}



}





int main(){
double count=0 ;
int a,b,c,d;

while(1){
tree.clear();callstack.clear();

tree.reserve(c=rand());
callstack.reserve(c);

// filling with random values    
fillwithrandom(&(a=0),&(b=0),c);
stack[b]--;

iterativetree(&(a=0));


printf(" %d univalued subtrees",a);printf("\n ");
system("pause"); 
}
}

online comparison

【讨论】:

    猜你喜欢
    • 2016-11-25
    • 2013-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-29
    • 1970-01-01
    • 2012-09-16
    • 1970-01-01
    相关资源
    最近更新 更多