按类型算法组合列表

时间:2014-09-16 19:48:08

标签: c++ algorithm

我正在尝试用C ++创建一个算法,它将为我提供一组列表项的所有可能组合(以地图格式输入)。我想避免重复,并确保涵盖所有可能的组合。为简化示例,输入可能如下所示:

map<string, vector<string> > sandwichMap;

sandwichMap["bread"].push_back("wheat");
sandwichMap["bread"].push_back("white");
sandwichMap["meat"].push_back("ham");
sandwichMap["meat"].push_back("turkey");
sandwichMap["meat"].push_back("roastbeef");
sandwichMap["veggie"].push_back("lettuce");
sandwichMap["sauce"].push_back("mustard");

我会将此地图输入算法,它应该吐出一个包含所有可能组合的向量(使用每种密钥类型之一):

wheat+ham+lettuce+mustard
wheat+turkey+lettuce+mustard
wheat+roastbeef+lettuce+mustard
white+ham+lettuce+mustard
white+turkey+lettuce+mustard
white+roastbeef+lettuce+mustard

它需要适用于任何字符串向量的映射。到目前为止,我已经尝试并接近了,但我最终得到了重复的组合和错过的组合:

sandwichList getCombinations(sandwichMap sMap)
{
    locList retList;
    int totalCombos = 1;

    for (sandwichMapIt i = sMap.begin(); i != sMap.end(); ++i)
    {
        totalCombos *= i->second.size();
    }

    retList.resize(totalCombos);
    int locCount;

    for (sandwichMapIt a = sMap.begin(); a != sMap.end(); ++a)
    {
        locCount = 0;
        for (locListIt l = a->second.begin(); l != a->second.end(); ++l)
        {
            for (unsigned int i = 0; i < totalCombos / a->second.size(); ++i)
            {
                retList[i + a->second.size() * locCount] += *l;
            }

            locCount++;
        }
    }

    return retList;
}

非常感谢任何帮助!

更新的代码:

#include <vector>
#include <map>
#include <list>
#include <iostream>

typedef std::vector<std::string> strVec;
typedef std::list<std::string> strList;
typedef std::map<std::string, strVec> sandwichMap;

int main()
{
    sandwichMap sMap;

    sMap["bread"].push_back("wheat");
    sMap["bread"].push_back("white");
    sMap["meat"].push_back("ham");
    sMap["meat"].push_back("turkey");
    sMap["meat"].push_back("roastbeef");
    sMap["veggie"].push_back("lettuce");
    sMap["sauce"].push_back("mustard");

    strList finalSandwichList;
    for (sandwichMap::iterator i = sMap.begin(); i != sMap.end(); ++i)
    {
        strList tmpSandwich;
        for (strVec::iterator j = i->second.begin(); j != i->second.end(); ++j)
        {
            if (finalSandwichList.empty())
            {
                tmpSandwich.push_back(*j);
            }
            else
            {
                for (strList::iterator k = finalSandwichList.begin(); k != finalSandwichList.end(); ++k)
                    tmpSandwich.push_back(*k + "+" + *j);
            }
        }
        tmpSandwich.swap(finalSandwichList);
    }

    for (strList::iterator i = finalSandwichList.begin(); i != finalSandwichList.end(); ++i)
    {
        std::cout << *i << std::endl;
    }

    return 0;
}

5 个答案:

答案 0 :(得分:1)

   //solution
  std::list<std::string> result;
  for(auto i=sandwichMap.begin(); i!=sandwichMap.end(); ++i) {
    std::list<std::string> new_result;
    for(auto j=i->second.begin(); j!=i->second.end(); ++j) {
      if(result.empty())
        new_result.push_back(*j);
      else
       for(auto k=result.begin(); k!=result.end(); ++k)
         new_result.push_back(*k + "+" + *j);
    }
    new_result.swap(result);
  }

答案 1 :(得分:0)

这应该有效:

#include<iostream>
#include<map>
#include<string>
#include<algorithm>

using namespace std;

map<string, vector<string>> sMap;
vector<string> add;
int sett[200], countt;

void solve(map<string, vector<string>>::iterator itt, int ct, vector<string> addd){
    vector<string> tmp = itt->second;
    if(ct == countt){
        for(int j=0;j<addd.size();j++){
            cout<<addd[j]<<" ";
        }
        cout<<endl;
        return;
    }
    itt++;
    for(int i=0;i<tmp.size();i++){
        //cout<<tmp[i]<<" ";
        addd.push_back(tmp[i]);
        solve(itt, ct+1, addd);
        vector<string>::iterator tempIt = addd.end();
        addd.erase(tempIt--);
    }
}

int main(){
    sMap["bre"].push_back("wh");
    sMap["bre"].push_back("whi");
    sMap["me"].push_back("ham");
    sMap["me"].push_back("tur");
    sMap["me"].push_back("rr");
    sMap["veg"].push_back("let");
    sMap["sau"].push_back("mus");
    countt = sMap.size();
    solve(sMap.begin(), 0, add);
return 0;
}

我使用回溯来评估每种可能的组合。 注意:在c ++ 11中,您可能需要更改c ++较低版本的代码的某些部分

链接到输出:http://ideone.com/Ou2411

答案 2 :(得分:0)

由于辅助方法,代码有点长,但它完成了这项工作:

#include <vector>
#include <string>
#include <map>
#include <iostream>
using namespace std;

template <class T>
vector<T> Head(const vector<T> &v) {
    return vector<T>(v.begin(), v.begin() + 1);
}

template <class T>
vector<T> Tail(const vector<T> &v) {
    auto first = v.begin() + 1;
    auto last = v.end();
    return vector<T>(first, last);
}

template <class T>
vector<T> Concat(const vector<T> &v1, const vector<T> &v2) {
    vector<T> result = v1;
    result.insert(result.end(), v2.begin(), v2.end());
    return result;
}


vector<vector<string>> CombineVectorWithScalar(const vector<vector<string>> &v, const string &scalar) {
    vector<vector<string>> result = v;
    for (unsigned i = 0; i < v.size(); i++) {
        result[i].push_back(scalar);
    }
    return result;
}

vector<vector<string>> CombineVectorWithVector(const vector<vector<string>> &v1, const vector<string> &v2) {
    if (v2.empty()) {
        return vector<vector<string>>();
    }
    else {
        auto headCombination = CombineVectorWithScalar(v1, v2.front());
        auto tailCombination = CombineVectorWithVector(v1, Tail(v2));
        return Concat(headCombination, tailCombination);
    }
}

vector<string> GetKeys(const map<string, vector<string>> &mp) {
    vector<string> keys;

    for (auto it = mp.begin(); it != mp.end(); ++it) {
        keys.push_back(it->first);
    }

    return keys;
}

vector<vector<string>> CombineMapValues(const map<string, vector<string>> &mp) {
    vector<string> keys = GetKeys(mp);

    vector<vector<string>> result;
    auto &firstVector = mp.begin()->second;
    for (auto it = firstVector.begin(); it != firstVector.end(); ++it) {
        vector<string> oneElementList;
        oneElementList.push_back(*it);
        result.push_back(oneElementList);
    }

    vector<string> restOfTheKeys = Tail(keys);
    for (auto it = restOfTheKeys.begin(); it != restOfTheKeys.end(); ++it) {
        auto &currentVector = mp.find(*it)->second;
        result = CombineVectorWithVector(result, currentVector);
    }

    return result;
}

void PrintCombinations(const vector<vector<string>> & allCombinations) {
    for (auto it = allCombinations.begin(); it != allCombinations.end(); ++it) {
        auto currentCombination = *it;
        for (auto itInner = currentCombination.begin(); itInner != currentCombination.end(); ++itInner) {
            cout << *itInner << " ";
        }
        cout << endl;
    }
}

int main() {
    map<string, vector<string> > sandwichMap;

    sandwichMap["bread"].push_back("wheat");
    sandwichMap["bread"].push_back("white");
    sandwichMap["meat"].push_back("ham");
    sandwichMap["meat"].push_back("turkey");
    sandwichMap["meat"].push_back("roastbeef");
    sandwichMap["veggie"].push_back("lettuce");
    sandwichMap["sauce"].push_back("mustard");

    auto allCombinations = CombineMapValues(sandwichMap);
    PrintCombinations(allCombinations);

    return 0;
}

答案 3 :(得分:0)

void generate_all(std::map<std::string,std::vector<std::string>>::iterator start,
 std::vector<std::string::iterator> accomulator,
 std::map<std::string,std::vector<std::string>>& sMap){
    for (auto it=start; it!=sMap.end(); ++it){
        for (auto jt=it->second.begin(); jt!=it->second.end(); jt++){
            generate_all(start+1,accomulator.pus_back[jt],sMap);
        }
    }
    if (accomulator.size() == sMap.size()){
        // print accomulator
    }
}

使用generate_all(sMap.begin(),aVector,sMap);

进行通话

如果地图太大而无法递归,您始终可以生成等效的迭代代码。

答案 4 :(得分:0)

此解决方案不是递归的。基本上它的作用如下:

  • 计算实际可能的组合数
  • 了解地图中的每个键,您必须总共添加nrCombinations/nrItemsInKey个。
  • 你可以看到它正在成长为一棵树,越来越多的分支你访问过的密钥越来越多。
  • 如果您跟踪它们的数量,它们之间的距离以及它们的起点,您可以自动填充所有组合。

代码

#include <vector>
#include <iostream>
#include <map>
#include <string>

int main() {
    std::map<std::string, std::vector<std::string> > sandwichMap;

    sandwichMap["bread"].push_back("wheat");
    sandwichMap["bread"].push_back("white");
    sandwichMap["meat"].push_back("ham");
    sandwichMap["meat"].push_back("turkey");
    sandwichMap["meat"].push_back("roastbeef");
    sandwichMap["veggie"].push_back("lettuce");
    sandwichMap["sauce"].push_back("mustard");
    sandwichMap["sauce"].push_back("mayo");

    // Compute just how many combinations there are
    int combinationNr = 1;
    for ( auto it : sandwichMap ) {
        combinationNr *= it.second.size();
    }
    std::vector<std::vector<std::string>> solutions(combinationNr);
    // We start with empty lists, thus we only have one cluster
    int clusters = 1, clusterSize = combinationNr;
    for ( auto category : sandwichMap ) {
        int startIndex      = 0;
        int itemsNr         = category.second.size();
        int itemsPerCluster = clusterSize / itemsNr;
        for ( auto item : category.second ) {
            for ( int c = 0; c < clusters; ++c ) {
                for ( int i = 0; i < itemsPerCluster; ++i ) {
                    // We sequentially fill each cluster with this item.
                    // Each fill starts offset by the quantity of items
                    // already added in the cluster.
                    solutions[startIndex+i+c*clusterSize].push_back(item);
                }
            }
            startIndex += itemsPerCluster;
        }
        clusters *= itemsNr;
        clusterSize = combinationNr / clusters;
    }

    for ( auto list : solutions ) {
        for ( auto element : list ) {
            std::cout << element << ", ";
        }
        std::cout << "\n";
    }
    return 0;
}