【问题标题】:Different ways of suming specific numbers to gain 100将特定数字相加以获得 100 的不同方法
【发布时间】:2011-06-25 12:59:54
【问题描述】:

我想写一段代码来说明有多少种方法可以将 5 个不同的数字相加得到 100。例如,数字是2,5,10,20,50,它们可以重复任意次数。这里50+50 是一种方式,20+20+20+20+20。我不知道如何编程。

我认为它应该通过递归函数来完成,并且我已经尝试在实际上不知道如何编写的情况下编写一个,所以这是我想出的最好的:

#include<iostream>
#include<vector>

using namespace std;


int i,sum,n=5,counter=0;


int add(vector<int> &m){

    if(m.size()==0) return 0 ;

    for(i=0 ; i<m.size() ; i++ ){

          sum=m[i]+add(m);
          cout<< sum<<endl;
        if(n>0) n--;
        m.resize(n);
    }


}


int _tmain(int argc, _TCHAR* argv[])
{
    int i,sum,n=5;

vector<int> m;

m.resize(5);

m[0]=2;
m[1]=5;
m[2]=10;
m[3]=20;
m[4]=50;

add(m);


    return 0;
}

【问题讨论】:

标签: c++ algorithm math


【解决方案1】:

这个问题理论上可以用generating functions解决。生成函数不是函数,它不会生成任何东西(好名字,嗯?),但它确实可以很好地跟踪信息。结果你的问题的答案是,路数等于x^100在展开式中的系数

1/(1-x^2) * 1/(1-x^5) * 1/(1-x^10) * 1/(1-x^20) * 1/(1-x^50) 

以下是原因的解释。回想一下1/(1-x) = 1 + x + x^2 + x^3 + ...。这是我们将用来解决问题的基本生成函数。

假设您有可以重复任意次数的数字 A、B、...、N(在您的示例中,它们是 2、5、10、20、50)。然后考虑(生成)函数

f(x) = 1/(1-x^A) * 1/(1-x^B) * ... * 1/(1-x^N)

f(x)x^M的系数是M的写法数为形式之和

M = a*A + b*B + ... + n*N

其中a,b,...,n 是非负整数。

为什么会这样? 因为展开式f(x) 中的任何单项式项都来自于从1/(1-x^A) 中取一个项,对于某些非负的a,它看起来像x^(a*A),类似地对于其他条款。由于指数相加,x^M 的系数是所有写出这样一个和得到M 的方式。

我知道这不是一个编程答案,但希望你可以利用这个想法来编写程序。

【讨论】:

  • 系数的答案是 196。
  • 一本很好的介绍性(但非常有用)的关于生成函数的免费书籍math.upenn.edu/~wilf/DownldGF.html
  • 另外,最好的书名。
【解决方案2】:

只是为了好玩

#include <iostream>
#include <vector>
#include <iterator>
#include <numeric>
#include <algorithm>

static const int terms[] = { 2,5,10,20,50,   /*end marker*/0 };

using namespace std;
typedef vector  <int> Solution;
typedef vector  <Solution> Solutions;

inline int Sum(const Solution& s)
{
    return accumulate(s.begin(), s.end(), 0);
}

template <typename OutIt>
    OutIt generate(const int target, const int* term, Solution partial, OutIt out)
{
    const int cumulative = Sum(partial); // TODO optimize

    if (cumulative>target)
        return out;         // bail out, target exceeded

    if (cumulative == target)
    {
        (*out++) = partial; // report found solution
        return out;
    } else
    {
        // target not reached yet, try all terms in succession
        for (; *term && cumulative+*term<=target; term++)
        {
            partial.push_back(*term);
            out = generate(target, term, partial, out); // recursively generate till target reached
            partial.pop_back();
        }
        return out;
    }
}

Solutions generate(const int target)
{
    Solutions s;

    generate(target, terms, Solution(), back_inserter(s));

    return s;
}

void Dump(const Solution& solution)
{
    std::copy(solution.begin(), solution.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
}

#ifdef _TCHAR
int _tmain(int argc, _TCHAR* argv[])
#else
int main(int argc, char* argv[])
#endif
{
    Solutions all = generate(100);
    for_each(all.rbegin(), all.rend(), &Dump);
    return 0;
}

0.02 美元


为了真正回答这个问题,我删除了所有不需要的解决方案输出,大大优化了代码。现在它的效率要高得多(我用target=2000 将它的基准测试速度提高了 25 倍)但它仍然无法扩展到更大的 targets...

#include <iostream>
#include <vector>

using namespace std;

size_t generate(const int target, vector<int> terms)
{
    size_t count = 0;

    if (terms.back()<=target)
    {
        int largest = terms.back();
        terms.pop_back();
        int remain = target % largest;

        if (!remain)
            count += 1;

        if (!terms.empty())
            for (; remain<=target; remain+=largest)
                count += generate(remain, terms);
    }

    return count;
}

int main(int argc, char* argv[])
{
    static const int terms[] = {2,5,10,20,50};
    std::cout << "Found: " << generate(1000, vector<int>(terms, terms+5)) << std::endl;
    return 0;
}

希望更智能的模运算开始反映 PengOne 关于解决这个问题的建议。

【讨论】:

  • 我个人会接受 PengOne 的回答。它只是用纯粹的知识把我弄糊涂了。还要注意他是如何解决这个问题的,我只是做了(不是很有效地)生成解决方案的愚蠢工作。还是谢谢!
【解决方案3】:

这是一个递归解决方案:http://ideone.com/ip98M

#include <iostream>

template<size_t N>
void find_combinations_helper(int total, const int (&denoms)[N], int denoms_used, int remaining, int (&counts)[N])
{
    if (remaining == 0) {
        int partial_sum = 0;
        for( int i = 0; i < denoms_used; ++i ) {
           if (counts[i]) {
               std::cout << counts[i] << "*" << denoms[i];
               partial_sum += counts[i] * denoms[i];
               if (partial_sum < total) std::cout << " + ";
           }
        }
        std::cout << "\n";
        return;
    }

    if (denoms_used == N) return;

    for( counts[denoms_used] = 0; remaining >= 0; (remaining -= denoms[denoms_used]), ++counts[denoms_used] )
        find_combinations_helper(total, denoms, denoms_used + 1, remaining, counts);
}

template<size_t N>
void find_combinations( int total, const int (&denoms)[N] )
{
    int solutions[N];
    find_combinations_helper(total, denoms, 0, total, solutions);
}

int main(void) {
    const int bill_denoms[] = { 50, 20, 10, 5, 2 };
    find_combinations(100, bill_denoms);
}

【讨论】:

  • 我要 +1 以使用有点晦涩的 const int (&amp;denoms)[N] 模板技巧,我在现实生活中从未考虑使用,除非在通用函数 'array_size' 中使用 :) 我的同事会有我的头,这是正确的
【解决方案4】:

这看起来不对:

m[0]=2;
...
m[0]=50;

不应该是 m[4]=50;?

编辑 您从不声明值 100,您如何知道何时达到 100?

【讨论】:

    【解决方案5】:

    你现在拥有的函数add 的代码会让你发生堆栈溢出:) 因为你在修改向量m 之前对add(m) 进行了递归调用。所以add 总是被一个未修改的向量调用,并且基本情况永远不会被击中。

    我不知道我是否抓住了你想做的事,但是呢:

    #include <iostream>
    #include <sstream>
    #include <vector>
    
    void add(int i, std::string s, int sum)
    {
        if (sum == 100)
        {
          std::cout << s << "=100" << std::endl;
          return;
        }
        if (sum > 100)
        {
           return;
        }
        if (sum < 100)
        {
          std::ostringstream oss;
          oss << s << "+" << i;
          add(i, oss.str(), sum+i);
        }
    }
    
    int main()
    {
      std::vector<int> m;
    
      m.resize(5);
    
      m[0]=2;
      m[1]=5;
      m[2]=10;
      m[3]=20;
      m[4]=50;
    
      // This loop will initiate m.size lines of recursive calls
      // one for each element of the array
      for (size_t i = 0; i < m.size(); i++)
      {
        add(m[i], "", 0);
      }
    
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-04
      • 1970-01-01
      • 2021-01-03
      • 1970-01-01
      • 1970-01-01
      • 2020-05-27
      • 2013-06-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多