Algorithm 查找与和列表相对应的对集

Algorithm 查找与和列表相对应的对集,algorithm,matching,subset-sum,Algorithm,Matching,Subset Sum,给出两个数字列表和一个总数列表(无任何特定顺序): 我如何才能找到所有对集dwhered[k]=(a[I],b[j]),从而c[k]=a[I]+b[j]从a和b使用对而不进行替换?(所有列表都可以有重复项) 对于c=[7,7,7]: d = [(1,6), (2,5), (3,4)] (1个答案,因为所有排列基本上是等价的) 我希望使用长度约为500的列表执行此操作,因此不可能进行简单的匹配/回溯搜索 >这里是C++中的蛮力方法。它不会删减等价的置换,例如对于c=[7,7,7] #includ

给出两个数字列表和一个总数列表(无任何特定顺序):

我如何才能找到所有对集
d
where
d[k]=(a[I],b[j])
,从而
c[k]=a[I]+b[j]
从a和b使用对而不进行替换?(所有列表都可以有重复项)

对于
c=[7,7,7]

d = [(1,6), (2,5), (3,4)]
(1个答案,因为所有排列基本上是等价的)


我希望使用长度约为500的列表执行此操作,因此不可能进行简单的匹配/回溯搜索

>这里是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;
}
#包括
#包括
#包括
#包括
使用名称空间std;
//数字3d匹配:x+y+z=b,其中
//x=a,y=b,z=-c,b=0
模板
矢量n3dmatch(矢量a、矢量b、矢量c){
矢量结果;
如果(a.size()!=b.size()| b.size()!=c.size())返回结果;
载体ap,bp;
排序(a.begin(),a.end());
排序(b.开始(),b.结束());
当(下一个置换(a.begin(),a.end());
执行{bp.push_back(b);}while(下一个置换(b.begin(),b.end());
对于(int i=0;i对于(intj=0;j
为了便于演示,我将遍历一个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}情况


这几乎就是我所能得到的。

你想要一组成对序列,其中集合中的每个序列都有与序列c匹配的总和吗?在第一个示例中,也是[(1,5),(1,6),(2,6)]--还有更多这样的——也包括在内?没有替代品。我试图解决的问题是,每个列表都包含学生的分数。我可以访问每个列表以及两者的总和,但想知道给定总分时,可能的子分数是多少。这是否会使问题更容易解决(或增加唯一解决方案的机会),我可以访问这些列表中的N个,并且可以查询数据库中任何子集的总计列表。这个问题在维基百科中描述为。它是NP-完全的。第三个集合是c的负数,b=0。好的,谢谢。啊,解决了一个大小不可忽略的数据集上的NP-完全问题。好时机。
S:
 + | 4 5 6 
 --|-------
 1 | / X / 
 2 | / / X
 3 | X / /

Solution = { (1,5) (3,4) (2,6) }
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) }