心胸决定格局,眼界决定境界...

从数列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);

  

posted @ 2019-02-26 16:43  WELEN  阅读(753)  评论(0)    收藏  举报