//All combinations to get a number.

#include <vector>
#include <algorithm>
#include <iostream>
#include <string>
#include <sstream>

using namespace std;

typedef unsigned int uint;

vector<uint> g_summands;

typedef vector<uint> _CombinationContainer;

class Combination
{
    _CombinationContainer _cc;

public:
    Combination(uint capacity = 0)
    {
        _cc.reserve(capacity);
    }
    
public:
    int Add(uint number)
    {
        _cc.push_back(number);
        return _cc.size() - 1;
    }
    void Replace(_CombinationContainer::iterator pos, const Combination &c)
    {
        _cc.erase(pos);
        _cc.insert(_cc.end(), c.begin(), c.end());
        sort(_cc.begin(), _cc.end());
        reverse(_cc.begin(), _cc.end());
    }
    uint Sum() const
    {
        uint r = 0;
        for(_CombinationContainer::const_iterator it = _cc.begin(); it < _cc.end(); it++)
        {
            r += *it;
        }
        return r;
    }
    _CombinationContainer::iterator begin()
    {
        return _cc.begin();
    }
    _CombinationContainer::iterator end()
    {
        return _cc.end();
    }
    _CombinationContainer::const_iterator begin() const
    {
        return _cc.begin();
    }
    _CombinationContainer::const_iterator end() const
    {
        return _cc.end();
    }
    uint operator[](int index)
    {
        return _cc[index];
    }
    const uint operator[](int index) const
    {
        return _cc[index];
    }
};

ostream& operator <<(ostream& op1, const Combination &op2)
{
    bool addPlusSign = false;
    for (_CombinationContainer::const_iterator it = op2.begin(); it < op2.end(); it++)
    {
        op1 << (addPlusSign ? " + " : (addPlusSign = true, "")) << (*it);
    }
    op1 << endl;
    return op1;
}

typedef vector<Combination> CombinationCollection;

CombinationCollection g_combinations;

//Decomposes a number in its minimum number of summands.
bool DecomposeNumber(uint number, Combination &c)
{
    vector<uint>::const_iterator it = g_summands.begin();
    while (it < g_summands.end() && (*it) >= number) it++;
    if (it == g_summands.end()) return false;
    uint n = number;
    do
    {
        //cout << "DecomposeNumber n:  " << n << endl;
        //cout << "DecomposeNumber (*it):  " << *it << endl;
        for (uint i = 0; i < n / (*it); i++) c.Add((*it));
        n -= (n / (*it)) * (*it);
        it++;
    } while (it < g_summands.end() && n);
    /*cout << "DecomposeNumber Sum:  " << c.Sum() << endl;
    if (c.Sum() == number)
    {
        cout << "DecomposeNumber Success:  " << c << endl;
    }
    else if (it >= g_summands.end())
    {
        cout << "DecomposeNumber Failure:  Iterator reached end of summands." << endl;
    }
    else
    {
        cout << "DecomposeNumber Failure:  " << n << endl;
    }*/
    return (c.Sum() == number);
}

void GenerateCombinations(const Combination& c)
{
    uint prevNumber = 0;
    for(_CombinationContainer::const_iterator it = c.begin(); it < c.end(); it++)
    {
        if ((*it) == prevNumber) continue;
        Combination newC = c;
        Combination newSubC;
        if (DecomposeNumber(*it, newSubC))
        {
            newC.Replace(newC.begin() + std::distance(c.begin(), it), newSubC);
            g_combinations.push_back(newC);
            GenerateCombinations(newC);
        }
        prevNumber = *it;
    }
}

void StartGenerateCombinations(uint number)
{
    Combination firstC;
    if (DecomposeNumber(number, firstC))
    {
        g_combinations.push_back(firstC);
        GenerateCombinations(firstC);
    }
}

int main()
{
    cout << "Summands:  ";
    string input;
    getline(cin, input);
    cout << input << endl;
    istringstream in(input);
    while (in.good())
    {
        uint summand;
        in >> summand;
        g_summands.push_back(summand);
    }
    sort(g_summands.begin(), g_summands.end());
    reverse(g_summands.begin(), g_summands.end());
    cout << "Summands input(" << g_summands.size() << "):  ";
    bool addSep = false;
    for (vector<uint>::const_iterator it = g_summands.begin(); it < g_summands.end(); it++)
    {
        cout << (addSep ? ", " : (addSep = true, "")) << (*it);
    }
    cout << endl;
    cout << "Number to decompose:  ";
    uint theNumber;
    input.clear();
    getline(cin, input);
    cout << input << endl;
    in.str(input);
    in.clear();
    in >> theNumber;
    if (!in.fail())
    {
        cout << "Number input to decompose is " << theNumber << "." << endl;
    }
    else
    {
        cout << "Invalid number typed.  Correct input and try again." << endl;
    }
    StartGenerateCombinations(theNumber);
    cout << "Total combinations:  " << g_combinations.size() << endl;
    addSep = false;
    for (CombinationCollection::const_iterator it = g_combinations.begin(); it < g_combinations.end(); it++)
    {
        cout << *it << endl;
    }
    return 0;
}
