【问题标题】:Finding set of pairs that correspond to list of sums查找与总和列表相对应的对组
【发布时间】:2013-02-28 09:38:02
【问题描述】:

给定两个数字列表和一个总计列表(没有任何特定顺序):

a = [1,2,3]
b = [4,5,6]
c = [6,7,8]

如何找到 d where d[k] = (a[i], b[j]) 的所有对集合,以便 c[k] = a[i] + b[j] where 对从 a 和 b 使用而无需替换? (所有列表都可以有重复)

d = [(1,5), (3,4), (2,6)]
d = [(2,4), (1,6), (3,5)]

对于c = [7,7,7]

d = [(1,6), (2,5), (3,4)]

(1 个答案,因为所有排列本质上都是等价的)

我想使用长度约为 500 的列表来执行此操作,因此天真的匹配/回溯搜索是不可能的。

【问题讨论】:

  • 您想要一组对序列,其中集合中的每个序列的总和与序列 c 匹配?此外,在第一个示例中,是否还会包含 [(1,5)、(1,6)、(2,6)] 以及更多此类内容?
  • 无替换。我要解决的问题是每个列表都包含学生的分数。我可以访问每个列表和两者的总和,但想知道给定总分,可能的子分数是多少。如果它使问题更容易解决(或增加唯一解决方案的机会),我可以访问这些列表中的 N 个,并且可以在数据库中查询其中任何子集的总计列表。
  • 这个问题在维基百科中被描述为Numerical 3-dimensional matching。它是 NP 完全的。
  • 第三组是 c 的负数,b = 0。好的,谢谢。
  • 啊,在不可忽略的大小数据集上解决一个 NP 完全问题。美好时光。

标签: algorithm matching subset-sum


【解决方案1】:

好的,修剪是蛮力方法。这需要 O(N^3)

为了便于演示,我将通过一个 N×N 正方形,它的和为 ab

S:
 + | 4 5 6 
 --|-------
 1 | 5 6 7 
 2 | 6 7 8
 3 | 7 8 9

我正在寻找构建 c={6,7,8}
我在 S 中找到了一个“6”。我将其删除,并将其行和列标记为不可用

S:
 + | 4 5 6 
 --|-------
 1 | / X / 
 2 | 6 / 8
 3 | 7 / 9

Solution = { (1,5) }

然后我试着找到一个'7'

S:
 + | 4 5 6 
 --|-------
 1 | / X / 
 2 | / / 8
 3 | X / /

Solution = { (1,5) (3,4) }

最后是“6”

S:
 + | 4 5 6 
 --|-------
 1 | / X / 
 2 | / / X
 3 | X / /

Solution = { (1,5) (3,4) (2,6) }

第一个循环('6' 的循环)将继续并找到另一个匹配项:(2,4)。这将形成第二个解决方案 { (2,4) (1,6) (3,5) }

现在,改进这一点的一种方法是使用一些动态编程:找出所有可能的组合,预先给出结果。

Given c={ 6 7 8}, create sets S_x where x is {6,7,8} and 
    S_x = { (i,j) } such that S[i][j]=x
So:
    S_6 = { (1,2) (2,1) }
    S_7 = { (1,3) (2,2) (3,1)  }
    S_8 = { (2,3) (3,2) }

现在,具有给定启发式的相同算法将在 O(S_l1 * S_l2 * ... S_lN) 中运行,其中 S_li 表示 S_i 的长度。

可能在一般情况下运行得更快。 它还将正确处理 c={7,7,7} 的情况。

这差不多就是我的全部了。

【讨论】:

    【解决方案2】:

    这是 C++ 中的蛮力方法。它不会修剪等价排列,例如对于 c=[7,7,7]。

    #include <vector>
    #include <iostream>
    #include <algorithm>
    #include <utility>
    
    using namespace std;
    
    // numerical 3d match: x + y + z = b where                                                                                         
    // x = a, y = b, z = -c, b = 0                                                                                                     
    template <typename T>
    vector<pair<vector<T>, vector<T> > > n3dmatch(vector<T> a, vector<T> b, vector<T> c) {
      vector<pair<vector<T>, vector<T> > > result;
      if (a.size() != b.size() || b.size() != c.size()) return result;
    
      vector<vector<T> > ap, bp;
      sort(a.begin(), a.end());
      sort(b.begin(), b.end());
      do { ap.push_back(a); } while (next_permutation(a.begin(), a.end()));
      do { bp.push_back(b); } while (next_permutation(b.begin(), b.end()));
    
      for (int i = 0; i < ap.size(); i++) {
        for (int j = 0; j < ap.size(); j++) {
          bool match = true;
          for (int k = 0; k < a.size(); k++) {
            if ((ap[i][k] + bp[j][k]) != c[k]) {
              match = false; break;
            }
          }
          if (match) result.push_back({ ap[i], bp[j] });
        }
      }
      return result;
    }
    
    int main(int argc, char *argv[]) {
      vector<int> a = { 1, 2, 3 };
      vector<int> b = { 4, 5, 6 };
      vector<int> c = { 6, 7, 8 };
      //vector<int> c = { 7, 7, 7 };                                                                                                   
      auto result = n3dmatch(a, b, c);
      for (int i = 0; i < result.size(); i++) {
        vector<int> &a = result[i].first;
        vector<int> &b = result[i].second;
        for (int j = 0; j < a.size(); j++) cout << a[j] << " "; cout << endl;
        for (int j = 0; j < b.size(); j++) cout << b[j] << " "; cout << endl;
        cout << "-" << endl;
      }
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-28
      • 2014-02-03
      • 2016-12-31
      • 2021-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多