Print all combinations of a number N, as a sum of positive integers?
They should be unique
示例
3 =
1 2
1 1 1
4=
3 1
2 2
1 1 2
1 1 1 1
我已经使用回溯为这个做了一个解决方案,但问题是它也提供重复,例如3
我正在
1 1 2
2 1 1
如何才能获得独特的组合?
许多人提前感谢
答案 0 :(得分:5)
当您创建背部时,您将始终从最后一个数字开始(第一次将1视为最后一个数字)(基本上您保留一个已排序的解决方案)这就是您始终保持唯一解决方案的方式。
#include <iostream>
const int N = 4;
int sol[N];
int sum = 0;
int nr_of_elements;
void back(int lastElement)
{
if (sum == N)
{
for (int i = 0 ; i < nr_of_elements; i++)
std :: cout << sol[i] << " ";
std :: cout << "\n";
return ;
}
for ( int i = lastElement ; i <= N - sum ; i++)
{
sum += i;
sol[nr_of_elements++] = i;
back(i);
sum -= i;
nr_of_elements--;
}
}
int main ()
{
back(1);
return 0;
}
答案 1 :(得分:3)
对于每个号码,您只需要检查大于或等于它的号码。例如:
1 1 1 1
1 1 2
1 2 1 (not this, as the third 1 is less than is precedent 2)
1 3
2 1 1 (not this)
2 2
3 1 (not this)
4
答案 2 :(得分:2)
这是Ionescu Roberts的Java版本答案:
static Set<List<Integer>> getNums(int last, int target) {
Set<List<Integer>> toReturn = new HashSet<List<Integer>>();
if (target == 0) {
toReturn.add(new ArrayList<Integer>());
return toReturn;
}
for (int i = last; i <= target; i++) {
for (List<Integer> subSolution : getNums(i, target - i)) {
List<Integer> seq = new ArrayList<Integer>(subSolution);
seq.add(i);
toReturn.add(seq);
}
}
return toReturn;
}
答案 3 :(得分:2)
传递用作参数的最后一个数字。
void rec(int lastUsed)
{
for (int i = lastUsed; i <= max; i++)
rec(i);
}
答案 4 :(得分:0)
解决给定问题的回溯的更清晰实现(参考算法设计手册:此处使用相同的模板)。
#define V(x) vector<x >
typedef V(int) VI;
bool isSolutionReached(VI & input, VI & partial, int k,int data) {
if (k==data) return true;
return false;
}
void processSolution(VI & input,VI & partial, int k,int data) {
int sum=0,i=0;
for(i=0;i<=data;i++)
if(partial[i]!=0 ) {
sum+=i;
}
if(sum == k) {
for(i=0;i<=data;i++)
if(partial[i]!=0) cout <<i<<"\t";
cout <<"\n";
}
}
void constructNext(VI & input,VI & candidateVector,int k,int data) {
candidateVector.push_back(0);
candidateVector.push_back(1);
}
bool finished=false;
void backTrack(VI & inp, VI &partial, int k,int data ) {
VI candidateVector;
int i=0;
if( isSolutionReached(partial,inp,k,data)) {
processSolution(inp,partial,k,data);
}else {
k=k+1;
constructNext(inp,candidateVector,k,data);
for(i=0;i<candidateVector.size();i++) {
partial[k]=candidateVector[i];
backTrack(inp,partial,k,data);
}
}
}
int main() {
int n=5; //This is x+1
VI inp(5,0);
VI partial(5,0);
backTrack(inp,partial,0,n-1);
return 0;
}
答案 5 :(得分:0)
这个答案适用于Java和C#等,你可以覆盖equals和hashcode。
最简单的方法是利用现有算法生成2 ^ N种可能的组合,但调整它以使用Set来消除重复。您的方法将返回一组所有组合,并且不包含重复项。现在您需要告诉Set如何识别2个重复组合:使用列表,并覆盖equals和hashcode方法。
您希望将组合存储在列表中,让我们调用包含java.util.ArrayList的UniqueList:
class UniqueList {
ArrayList data = new ArrayList();
void add(Integer item) {
data.add(item);
}
//more wrapper calls if you want
@Override
public boolean equals(UniqueList anotherList) {
if (data.size() != anotherList.data.size()) return false
//only need to sort once in each list
Collections.sort(data);
Collections.sort(anotherList.data);
for (int i = 0; i < data.size(); i++) {
if (data.get(i) != anotherList.data.get(i)) return false
}
return true;
}
//optionally override hashcode for performance on hashtable
}
现在在现有的生成算法中,使用
Set<UniqueList<Integer>>
保持组合,它将保证没有重复,因为Set将在允许组合之前使用equals()方法进行检查。
您可以添加一个布尔标志来指示列表是否已经排序以避免重复排序 - 换句话说,每个列表只需要排序一次,以便检查重复。
这种方法显然不是最佳方法,但您可以将其插入现有算法中,以最少的代码更改实现0次重复。