给出两个数字列表和一个总数列表(没有任何特定顺序):
a = [1,2,3]
b = [4,5,6]
c = [6,7,8]
如何在d
找到所有d[k] = (a[i], b[j])
对c[k] = a[i] + b[j]
,以便在没有替换的情况下从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}}
(1个答案,因为所有排列基本相同)
我想用长度约为500的列表来做这个,所以天真的匹配/回溯搜索是不可能的。
答案 0 :(得分:1)
好的,有修剪的蛮力方法。这需要O(N ^ 3)
为了便于演示,我将通过N-by-N广场,其总和为 a 和 b
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}的情况。
这就是我的全部。
答案 1 :(得分:0)
这是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;
}