【问题标题】:Yet another logic又一个逻辑
【发布时间】:2011-01-04 23:11:07
【问题描述】:

出于好奇,我正在研究一个研究问题,但我不知道如何编写我想到的逻辑。让我给你解释一下:

例如,我有四个向量,

v1 = 1 1 1 1
v2 = 2 2 2 2
v3 = 3 3 3 3
v4 = 4 4 4 4

我想以组合方式添加它们。也就是说,

v12 = v1+v2
v13 = v1+v3
v14 = v1+v4
v23 = v2+v3
v24 = v2+v4
v34 = v3+v4

到这一步就好了。现在的问题/技巧是,在每次迭代结束时,我将获得的向量放入一个黑盒函数中,它只返回几个向量,比如 v12、v13 和 v34。现在,我想将这些向量中的每一个添加一个来自 v1、v2、v3、v4 的向量,这是它之前没有添加的。比如v3和v4还没有添加到v12,所以我想创建v123和v124。类似地,对于所有的向量,

v12 should become:
v123 = v12+v3
v124 = v12+v4

v13 should become:
v132 // This should not occur because I already have v123
v134 = v13+v4;

v14、v23 和 v24 不能考虑 因为被黑删了 盒子功能,所以我们在我们的 手动使用的是 v12、v13 和 v34。

v34 should become:
v341 // Cannot occur because we have 134
v342 = v34+v2

重要的是我不要一开始就一步到位。例如,我可以做(4 选择 3)4C3 并完成它,但我想在每次迭代时一步一步地做。

包含黑匣子功能怎么办?

【问题讨论】:

  • 只是为了澄清一下,当您说添加时,您的意思是合并而不是值的总和,对吗?所以 v1+v2 => 11112222
  • 我的意思是添加像 v12 = 3333 这样的值。就像在 C++ 中使用加号运算符来添加两个向量一样。
  • 也就是说,这个“向量”真的更像std::valarray
  • @rob:我不熟悉valarray。这是我第一次听到。对不起。
  • 别担心,@Sunil。我几乎没有看到它被任何人使用过。使用它会使您的加法操作更容易,也可能使人们更容易理解您的问题,但我认为它最终不会影响您的问题。您只需要跟踪您组合了哪些值; 如何组合它们(无论是通过添加、连接还是其他方式)并不重要。

标签: c++ algorithm vector combinations


【解决方案1】:

好的,就这样吧,这可能会更有效,但我认为这可以满足您的需要。

#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <set>
#include <map>

using namespace std;

typedef vector<int> v_t;
typedef set<int> s_t;
typedef map<s_t, v_t> m_t;
typedef vector<pair<s_t, v_t> > b_t;

// this inserts a new entry into the map with the provided key
// the value_type (vector) is generated by adding the entries in each vector
// NOTE: the first vector is passed by value (so we get a copy in the function)
// the second vector (passed by ref) is then added to it.
void insert_entry(m_t& dest, s_t& key, v_t vdest, v_t const& v2)
{
  v_t::const_iterator it2(v2.begin());
  // there is no global operator+ for vector, so you have to do something like below
  for(v_t::iterator it(vdest.begin()), end(vdest.end()); it != end && (*(it++) += *(it2++)););
  // this is just debug
  cout << "new key: " << key.size() << " : ";
  copy(key.begin(), key.end(), ostream_iterator<int>(cout, " "));
  cout << endl;
  cout << "vec: ";
  copy(vdest.begin(), vdest.end(), ostream_iterator<int>(cout, " "));
  // actual insert in to map
  // for example, key may be set<1, 2> and value is vector <3, 3, 3, 3>
  dest.insert(dest.end(), make_pair(key, vdest));
  cout << "size of dest: " << dest.size() << endl;
}

// This function generates all unique combinations of a given size and inserts them into 
// the main map
void gen_comb(size_t cmb, b_t const& base, m_t& dest)
{
  typedef m_t::iterator m_it;

  cout << "combination size: " << cmb << endl;

  // Now calculate our starting vector key size, a "key" is imply a combination of
  // vectors, e.g. v12, v23 v14 etc. in this case key size = 2 (i.e. two vectors)
  // If we need to generate combinations of size 3 (cmb=3), then we start with all
  // vectors of key size = 2 (v12, v23, v14 etc.) and add all the base (v1, v2 v3) to it
  size_t s_ksz = cmb - 1; // search key size
  cout << "search size: " << s_ksz << endl;
  // now iterate through all entries in the map
  for(m_it it(dest.begin()); it != dest.end(); ++it)
  {
    // Aha, the key size matches what we require (for example, to generate v123, we
    // need v12 (key size == 2) first
    if (it->first.size() == s_ksz)
    {
      // Now iterate through all base vectors (v1, v2, v3, v4)
      for(b_t::const_iterator v_it(base.begin()), v_end(base.end()); v_it != v_end; ++v_it)
      {
        // new key, start with the main key from map, e.g. set<1, 2>
        s_t nk(it->first.begin(), it->first.end());
        // Add the base key set<3>, reason I do it this way is that, in case you
        // that base vectors should be other than size 1 (else insert(*((*v_it)->first.begin())) should work just fine.
        nk.insert(v_it->first.begin(), v_it->first.end());
        // check if this key exists, this is the main check, this tests whether our map
        // already has a key with the same vectors (for example, set<1,2,3> == set<2,3,1> - internally set is ordered)
        m_it k_e = dest.find(nk);
        // If the key (combination of vectors) does not exist, then insert a new entry
        if (k_e == dest.end())
        {
          // new key
          insert_entry(dest, nk, it->second, v_it->second);
        }
      }
    }
  }
}

void trim(size_t depth, m_t& dest)
{
  for(m_t::iterator it(dest.begin()); it != dest.end();)
  {
    if (it->first.size() == depth && (rand() % 2))
    {
      cout << "removing key: " << depth << " : ";
      copy(it->first.begin(), it->first.end(), ostream_iterator<int>(cout, " "));
      cout << endl;
      dest.erase(it++);
    }
    else
      ++it;
  }
}

int main(void)
{
  // combination map
  m_t dest;

  // this is the set of bases
  b_t bases;
  int max_i = 4;
  for(int i = 1; i <= max_i; ++i)
  {
    v_t v(4, i);
    s_t k;
    k.insert(i);
    bases.push_back(make_pair(k, v));
  }

  // for the start, push in the bases
  dest.insert(bases.begin(), bases.end());

  // for each combination size, generate a new set of vectors and then trim that set.
  for (size_t cmb = 1; cmb <= static_cast<size_t>(max_i); ++cmb)
  {
    if (cmb > 1) gen_comb(cmb, bases, dest);
    trim(cmb, dest); // randomly remove some entries...
  }


  return 0;
}

注意事项:

  1. trim 函数为您的黑盒建模,该黑盒使用给定的键大小(与最近生成的组合大小相同)从主地图中删除一些条目
  2. 我不确定迭代映射和插入新条目的有效性(即它如何影响迭代器,它似乎可以工作,但我认为我可能遗漏了一些微妙的东西 - 为时已晚晚上考虑一下!)
  3. 性能可能并不理想,因为您需要遍历所有键才能找到搜索大小(用于组合)。
  4. 假设所有向量的大小都相同(但这可以很容易地修复)
  5. 如果你把debug拿出来,你会发现实际的代码很小..
  6. 没有保留组合的顺序 - 不确定这对您是否有必要

编辑: 好的,现在 base 是一个向量,其中包含一个 pair 用于键向量关系 - 这是恒定的。最初它被添加到地图中,并且 gen_comb 函数被跳过初始状态,trim 仍然被调用以删除一些条目。下一次迭代使用相同的搜索算法,但组合使用bases 的常量集。

【讨论】:

  • 你忘记了#include &lt;map&gt;。这就是为什么我有这么多错误。 :-)
  • 我认为这个逻辑很完美,但我仍在努力理解它。更多的 cmets 将非常有帮助。谢谢
  • @Nim:我有一个小问题。在这里,您的修剪函数采用键和向量对(即整个地图)并将其修剪在一起,但我的黑盒函数将 2d 向量作为输入并输出修剪后的 2d 向量(删除向量内的某些向量)。我可以将程序中的独立 1d 向量转换为 2d 向量,但是我怎样才能保持匹配呢?请帮帮我。黑盒功能完成后,我发现很难保持匹配。非常感谢。
  • @Sunil,哎呀键盘没有抱怨,反正会编辑更多的 cmets。想必你不能修改函数来取图吧?嗯,这很棘手 - 黑盒函数,它是否需要一个向量(向量),其中它们的密钥大小相同(即所有向量只有密钥大小为 2,然后是 3,然后是 4 等)?此外,它是在位置上修剪还是修剪所有相同的向量(例如,v23 == v14)?
  • 如果你改变 for 循环使得cmb=1,在gen_comb 周围添加一个if 这样它就不会在cmb==1 时生成组合,那么你仍然可以调用你的黑色带有仅包含基本数组的地图的 box 函数,这应该可以工作。
猜你喜欢
  • 2021-10-11
  • 1970-01-01
  • 1970-01-01
  • 2018-01-21
  • 2012-12-11
  • 2017-08-10
  • 1970-01-01
  • 2019-07-04
  • 2012-09-20
相关资源
最近更新 更多