C++ 程序崩溃,树太大

C++ 程序崩溃,树太大,c++,recursion,tree,C++,Recursion,Tree,我试图通过练习来回答这个问题: 这里是一个盒子里的{50,25,10,5,1}美分的硬币。编写一个程序,通过对硬币进行分组,找出1美元的创造方法 我的解决方案是制作一棵树,每一条边都有上面的一个值。每个节点将持有一笔硬币。然后我可以填充这棵树,并寻找总共100片叶子。这是我的代码 class TrieNode { public: TrieNode(TrieNode* Parent=NULL,int sum=0,TrieNode* FirstChild=NULL,int children=

我试图通过练习来回答这个问题:

这里是一个盒子里的{50,25,10,5,1}美分的硬币。编写一个程序,通过对硬币进行分组,找出1美元的创造方法

我的解决方案是制作一棵树,每一条边都有上面的一个值。每个节点将持有一笔硬币。然后我可以填充这棵树,并寻找总共100片叶子。这是我的代码

class TrieNode
{
public:
    TrieNode(TrieNode* Parent=NULL,int sum=0,TrieNode* FirstChild=NULL,int children=0, bool key =false )
        :pParent(Parent),pChild(FirstChild),isKey(key),Sum(sum),NoChildren(children)
    {
        if(Sum==100)
            isKey=true;
    }
    void SetChildren(int children)
    {
        pChild = new TrieNode[children]();
        NoChildren=children;
    }
    ~TrieNode(void);

    //pointers
    TrieNode* pParent;
    TrieNode* pChild;

    int NoChildren;

    bool isKey;
    int Sum;
};

void Populate(TrieNode* Root, int coins[],int size)
{
    //Set children
    Root->SetChildren(size);

    //add children
    for(int i=0;i<size;i++)
    {
        TrieNode* child  = &Root->pChild[0];
        int c = Root->Sum+coins[i];
        if(c<=100)
        {
            child = new TrieNode(Root,c);

            if(!child->isKey) //recursively populate if not a key
                Populate(child,coins,size);
        }
        else 
            child = NULL;
    }
}

int getNumKeys(TrieNode* Root)
{
    int keys=0;

    if(Root == NULL)
        return 0;

    //increment keys if this is a key
    if(Root->isKey)
        keys++;

    for(int i=0; i<Root->NoChildren;i++)
    {
        keys+= getNumKeys(&Root->pChild[i]);
    }

    return keys;
}

int _tmain(int argc, _TCHAR* argv[])
{
    TrieNode* RootNode = new TrieNode(NULL,0);
    int coins[] = {50,25,10,5,1};
    int size = 5;

    Populate(RootNode,coins,size);
    int combos =  getNumKeys(RootNode);

    printf("%i",combos);

    return 0;
}
类三节点
{
公众:
三节点(三节点*父节点=NULL,整数和=0,三节点*第一子节点=NULL,整数子节点=0,布尔键=false)
:p父母、子女(第一个子女)、isKey(关键)、Sum(总和)、NoChildren(子女)
{
如果(总和=100)
isKey=true;
}
void SetChildren(int children)
{
pChild=新三元组[儿童]();
无子女=儿童;
}
~3reeode(void);
//指针
三节点*pParent;
三元组*pChild;
国际儿童;
布尔伊斯基;
整数和;
};
空白填充(三元组*根,整数硬币[],整数大小)
{
//安排孩子
根->设置子对象(大小);
//添加子项
for(int i=0;ipChild[0];
int c=根->总和+硬币[i];
if(cisKey)//如果不是键,则递归填充
填充(儿童、硬币、大小);
}
其他的
child=NULL;
}
}
int getNumKeys(三节点*根)
{
int键=0;
if(Root==NULL)
返回0;
//如果这是一个关键点,则增加关键点
如果(根->isKey)
按键++;
for(int i=0;iNoChildren;i++)
{
keys+=getNumKeys(&Root->pChild[i]);
}
返回键;
}
int _tmain(int argc,_TCHAR*argv[]
{
三节点*根节点=新的三节点(NULL,0);
国际货币[]={50,25,10,5,1};
int size=5;
填充(根节点、硬币、大小);
int combos=getNumKeys(RootNode);
printf(“%i”,组合);
返回0;
}
问题是树太大了,几秒钟后程序就崩溃了。我在Windows7四核上运行这个,内存为8gb。粗略计算一下,我应该有足够的内存

我的计算错了吗? 操作系统是否限制我可以访问多少内存? 我可以在仍然使用此解决方案的情况下修复它吗

感谢所有反馈。谢谢

Edit1: 我已经验证了上述方法是错误的。通过尝试用一组只有1枚硬币的硬币来构建一棵树。 硬币[]={1}

我发现算法仍然失败。 在阅读了Lenik和João Menighin的帖子之后 我提出了这个解决方案,将这两个想法联系在一起,形成一个递归解决方案 它需要任意大小的数组

//N is the total the coins have to amount to
int getComobs(int coins[], int size,int N)
{
    //write base cases
    //if array empty | coin value is zero or N is zero
    if(size==0 || coins[0]==0 ||N==0)
        return 0;


    int thisCoin = coins[0];
    int atMost = N / thisCoin ;

    //if only 1 coin denomination
    if(size==1)
    {
        //if all coins fit in N
        if(N%thisCoin==0)
            return 1;
        else
            return 0;
    }


    int combos =0;
    //write recursion
    for(int denomination =0; denomination<atMost;denomination++)
    {
        coins++;//reduce array ptr

        combos+= getComobs(coins, size-1,N-denomination*thisCoin);

        coins--;//increment array ptr
    }

    return combos;
}
//N是硬币总数
int GETCOMOB(整数硬币[],整数大小,整数N)
{
//写基本情况
//如果数组为空|币值为零或N为零
如果(大小==0 | |硬币[0]==0 | | N==0)
返回0;
int thisCoin=硬币[0];
int atMost=N/此币;
//如果只有1个硬币面额
如果(大小==1)
{
//如果所有的硬币都适合N
如果(N%thisCoin==0)
返回1;
其他的
返回0;
}
整数组合=0;
//写递归

对于(int-demination=0;demination问题可能是无限递归。在任何地方都不能递增c,循环使用c运行。我需要更多时间来分析代码,但现在我可以看出这是一个经典的动态规划问题。您可以在这里找到一些有趣的文本:

这里呢


好的,这不是一个完整的答案,但可能会对您有所帮助。 你可以试着做一次(我称之为)精神检查。 为每个创建的节点在
trinode
中放置一个
static
计数器,看看它增长了多大。如果你做了一些计算,你应该能够判断它是否达到了一些疯狂的值

系统可以限制可用内存,但这真的很奇怪。通常用户/管理员可以出于某些目的设置此类限制。这种情况在专用多用户系统中经常发生。其他情况可能是在64位windows环境中有一个32位的应用程序。然后mem限制将是4GB,但这也会很奇怪。我不知道我认为受操作系统的限制是一个问题


另一方面,我希望您能意识到,您用以下代码击败了所有面向对象的编程概念:)。

有一种更容易找到解决方案的方法:

#include <iostream>
#include <cstring>
using namespace std;
int main() {
    int w[101];
    memset(w, 0, sizeof(w));
    w[0] = 1;
    int d[] = {1, 5, 10, 25, 50};
    for (int i = 0 ; i != 5 ; i++) {
        for (int k = d[i] ; k <= 100 ; k++) {
            w[k] += w[k-d[i]];
        }
    }
    cout << w[100] << endl;
    return 0;
}
#包括
#包括
使用名称空间std;
int main(){
int w[101];
memset(w,0,sizeof(w));
w[0]=1;
int d[]={1,5,10,25,50};
对于(int i=0;i!=5;i++){

对于(int k=d[i];k树解决方案在这个问题上是完全错误的。这就像抓了10e6只老虎,然后只放了一只,因为你需要一只老虎。非常耗时和内存消耗——99.999%的节点是无用的,应该首先忽略

还有另一种方法

  • 请注意,您不能使一美元包含超过两个50美分
  • 请再次注意,您不能使一美元包含超过四个25美分的硬币
  • 注意……(你明白了吗?)
那么您的解决方案很简单:

for( int fifty=0; fifty<3; fifty++) {
    for( int quarters=0; quarters<5; quarters++) {
        for( int dimes=0; dimes<11; dimes++) {
            for( int nickels=0; nickels<21; nickels++) {
                int sum = fifty * 50 + quarters * 25 + dimes * 10 + nickels * 5;
                if( sum <= 100 ) counter++;  // here's a combination!!
            }
        }
    }
}

for(int-teno=0;teno我真的相信必须有人提出最有效、最简单的实现,这是对lenik答案的改进:
内存:常数

运行时间:考虑100为n,则运行时间约为O(n(lg(n)))作为反馈:在构造函数中避免使用3个以上的参数,改用setters。仅仅是这一事实就让你的代码更难阅读。如果这是一次面试,面试官可能不会喜欢这种情况。@Marcelvaldezorzco使用setters打破了ROI范式。@Marcell,在一个拥有一切的类中对大型构造函数进行了评论
public
和处理类属性的函数,这些都不是它的方法……考虑到OOP范式和编码标准,我认为这段代码存在更大的问题。lol.Good s
for( int fifty=0; fifty<3; fifty++) {
    for( int quarters=0; quarters<5; quarters++) {
        for( int dimes=0; dimes<11; dimes++) {
            for( int nickels=0; nickels<21; nickels++) {
                int sum = fifty * 50 + quarters * 25 + dimes * 10 + nickels * 5;
                if( sum <= 100 ) counter++;  // here's a combination!!
            }
        }
    }
}
for(int fifty=0; fifty <= 100; fifty+=50)
    for(int quarters=0; quarters <= (100 - fifty); quarters+=25)
        for(int dimes=0; dimes <= (100 - fifty - quarters); dimes+=10)
            counter += 1 + (100 - fifty - quarters - dimes)/5;