有俩种思路:
1,用01背包的方法,要么出现,要么不出现。再者去重,只需减去曾经出现过的枝条即可,具体见代码。
2,使用二进制模仿。但是不能超过整形大小,此处设为31(要移位的问题)。
#include <iostream>
#include <string>
#include "vld.h"
using namespace std;
void combine_str(string str);
void combine(string str,int level,string &res,bool *used);
bool is_repeat(string str ,int k,bool *used);
void bin_set(string str);
int main()
{
string str = "abc";//aac
combine_str(str);
cout<<"---------------"<<endl;
bin_set(str);
return 0;
}
void combine_str(string str)
{
if (str.empty())
{
return;
}
string res;
bool *used = new bool[str.size()];
memset(used,false,sizeof(bool)*str.size());
combine(str,0,res,used);
delete []used;
}
void combine(string str,int level,string &res,bool *used)
{
if (level >= str.size())
{
if (res.empty())
{
cout<<"empty"<<endl;
}
else
{
cout<<res<<endl;
}
return;
}
if (!is_repeat(str,level,used))//剪枝,去掉重复的
{
used[level] = false;
combine(str,level+1,res,used);
}
used[level] = true;
res.push_back(str[level]);
combine(str,level+1,res,used);
res.erase(res.size()-1,1);
}
bool is_repeat(string str ,int k,bool *used)
{
if (k >= str.size())//输入错也为真
{
return true;
}
for (int i = 0;i < k;i++)
{
if (str[k] == str[i]&&used[i])//前面未出现过,并使用过了的
{
return true;
}
}
return false;
}
void bin_set(string str)//可用简便的办法去重,判断每次输出的前面是否出现过!
{
if (str.empty())
{
return;
}
if (str.size() > 31)//大于int的范围
{
return ;
}
int n = 1<<str.size();
for (unsigned int i = 0;i < n;i++)
{
unsigned int t = i;
unsigned int index = 0;
while(t > 0)
{
if (t&1)
{
cout<<str[index];
}
index++;
t >>= 1;
}
if(i == 0)
{
cout<<"empty";
}
cout<<endl; //空的时候也输出
}
}
题目:输入两个整数n和m,从数列1,2,3...n中随意取几个数,使其和等于m,要求列出所有的组合。
好像是中兴的。也是01背包法,只需判断 1,sum == m 再者 level <= n