从数列1,2,3…….n 中随意取几个数, 使其和等于m 几种变形
输入两个整数n 和m,从数列1,2,3…….n 中随意取几个数(不可重复),
使其和等于m ,要求将其中所有的可能组合列出来。
递归,知道sum ==0结束
每次尝试一个数,剩下的就是补差,
不尝试这个数,剩下的补
排列的话,有长度,逐个逐个的赋值,原始可重复,设定条件可过滤重复,一般会用到cur位置
/*输入两个整数n 和m,从数列1,2,3…….n 中随意取几个数,
使其和等于m ,要求将其中所有的可能组合列出来(不可以重复选)。
*/
list<int> list_data;
void find_groups(int n, int m_sum)// 每次尝试一个数,sum就减少一个数
{ //如果想插入一个cur变量,cur的长度范围是多少,不知道
if (m_sum == 0)//找到
{
for (list<int>::iterator iter = list_data.begin(); iter != list_data.end(); iter++)
{
cout << *iter << " ";
}
cout << endl;
return;//找到了打印出来,返回,无需再往下继续了
}
if ( m_sum < 0 || n <= 0)//这次尝试不成功
{
return;
}
//从n到1这样去试
list_data.push_back(n);
find_groups(n - 1, m_sum - n);//尝试本次的数,则剩下的n-1~1组合出sum-n
list_data.pop_back();
find_groups(n - 1, m_sum);//不尝试本次的数,用剩下的n-1~1组合出sum
}
find_groups(5, 7);
//上面是1~n,现在是a1~an
//给定整数a1、a2、.......an,判断是否可以从中选出若干数,使它们的和恰好为K。
//问题一:有负数?还是都是正整数
//需要排序吗?排序有可能减少暴力范围,貌似正负都没有影响
//可以重复选择吗?貌似不行
//每个数都是可选和不可选,类似于01背包
//和生成子集系列还是有所不同
void find_groups_any(int* data, int n, int m_sum)// 每次尝试一个数,sum就减少一个数
{ //如果想插入一个cur变量,cur的长度范围是多少,不知道
if (m_sum == 0)//找到
{
for (list<int>::iterator iter = list_data.begin(); iter != list_data.end(); iter++)
{
cout << *iter << " ";
}
cout << endl;
return;//找到了打印出来,返回,无需再往下继续了
}
if (m_sum < 0 || n <= 0)//这次尝试不成功
{
return;
}
//从n到1这样去试
list_data.push_back(data[n - 1]);
find_groups_any(data, n - 1, m_sum - data[n - 1]);//尝试本次的数,则剩下的n-1~1组合出sum-n
list_data.pop_back();
find_groups_any(data, n - 1, m_sum);//不尝试本次的数,用剩下的n-1~1组合出sum
}
//还是一种就是指定 k个数的和为T,不像上面,数目是没有限制要求的 那就尝试一个数,k-1,同时差也变化,递归到结束
void find_groups_any_k(int* data, int n, int m_sum, int cnt)// 每次尝试一个数,sum就减少一个数
{ //如果想插入一个cur变量,cur的长度范围是多少,不知道
if (m_sum == 0 && cnt == 0)//找到
{
for (list<int>::iterator iter = list_data.begin(); iter != list_data.end(); iter++)
{
cout << *iter << " ";
}
cout << endl;
return;//找到了打印出来,返回,无需再往下继续了
}
if (m_sum < 0 || n <= 0 || cnt <= 0)//这次尝试不成功
{
return;
}
//从n到1这样去试
list_data.push_back(data[n - 1]);
find_groups_any_k(data, n - 1, m_sum - data[n - 1], cnt-1);//尝试本次的数,则剩下的n-1~1组合出sum-n
list_data.pop_back();
find_groups_any_k(data, n - 1, m_sum, cnt);//不尝试本次的数,用剩下的n-1~1组合出sum
}
//以上用01背包这种形式,来组合选择,也可以用DFS的形式来做
int n, k, ok, vis[22],count1;
void DFS(int pos, int *arr){//DFS 不完美
if (count1 >= k){//k是目标和 还必须得是正整数,如果出现负数呢
if (count1 == k){//如果找到了 如果后面出现元素0呢
if (!ok){
ok = 1; printf("YES\n");
}
for (int i = 0; i < n; ++i)//打印出选择的元素, 选择的元素标记为1
if (vis[i]) printf("%d ", arr[i]);
printf("\n");
}
return;
}
for (int i = pos; i < n; ++i){//逐个位置由左到右移动
count1 += arr[i];//尝试添加该元素
vis[i] = 1;//标记第i元素已经选中,递归后面的元素
DFS(i + 1, arr);//递归下一个pos,到最后的元素
count1 -= arr[i];//删除刚才尝试过的元素,相当于该位置没有选中,
vis[i] = 0;//标记为没有访问
}
}
int num_data[10] = { 1, 3, 2, 5, 4, 7, 6, 8, 9, 0 };
find_groups_any( num_data, 10, 7);
cout << endl;
count1 = 0;
n = 10;
k = 7;
DFS(0, num_data);
cout << endl;
find_groups_any_k(num_data, 10, 7, 3);
find_groups(5, 7);
//如果是a1~an ,可以重复选择挑选,上面又不适用了
int cur_sum;
void DFS_baoli(int *arr, int len, int cur, int cur_sum, int T)
{
if (cur_sum >= T || cur >= len)//假设都是正整数
{
if (cur_sum == T)
{
for (list<int>::iterator iter = list_data.begin(); iter != list_data.end(); iter++)
{
cout << *iter << " ";
}
cout << endl;
}
return;
}
for (int i = 0; i < len; i++)
{
cur_sum += arr[i];
list_data.push_back(arr[i]);
DFS_baoli(arr, len, cur + 1, cur_sum, T);//逐个位置,cur+1, 但是每个位置可以有len种选择
list_data.pop_back();//将上一个不选中,尝试下一种可能
cur_sum -= arr[i];
}
}
int num_data[10] = { 1, 3, 2, 5, 4, 7, 6, 8, 9, 10 };
DFS_baoli(num_data, 10, 0, 0, 7);

浙公网安备 33010602011771号