• 组合数的题型


    标准的C(n,m)求解

    • 包括输出所有组合数
    #if 0
    
    // 对于求C(n, m),从第一个字符开始扫描,每个字符有两种情况,要么被选中,要么不被选中,如果被选中,递归求解C(n-1, m-1)。
    // 如果未被选中,递归求解C(n-1, m)。不管哪种方式,n的值都会减少,递归的终止条件n=0或m=0。
    
    // 数组的全组合数
    void combination(vector<int> src, int i,int m, vector<int> &res, vector<vector<int>> &vecs)
    {
    	if (i>=src.size()&&m!=0)
    	{
    		return;
    	}
    	if (m==0) //递归终止条件
    	{
    		copy(res.begin(), res.end(), ostream_iterator<int>(cout, " "));
    		cout << endl;
    		return;
    	}  
    	//选择该元素
    	res.push_back(src[i]);
    	combination(src, i + 1, m - 1, res, vecs);
    	res.pop_back();
    	//不选该元素
    	combination(src, i+1, m, res, vecs);
    
    	return;
    }
    
    int main()
    {
    
    	int m, n;
    	cin >> m >> n; //C(n,m)
    	vector<int> input;
    	for (int i = 0; i < n;i++)
    	{
    		input.push_back(i + 1);
    	}
    
    	vector<vector<int>> vecs;
    	vector<int> vec;
    	//combination(input,0, m, vec, vecs); ////C(n,m)
    
    
    	for (int i = 1; i <= n;i++) //C(n, 1), C(n, 2),...C(n, n)的总和
    	{
    		combination(input,0,i,vec,vecs); ////C(n,m)
    	}
    
    	return 0;
    }
    
    
    #endif
    
    • 结果

    题目

    链接:https://www.nowcoder.com/questionTerminal/dd7fe2adc9ec4da5a91da1e224a7ad55
    来源:牛客网
    
    科室素拓进行游戏,游戏规则如下:随机抽取9个人作为游戏参与人员,分别编号1至9,每轮要求k(k<=9且k>=0)个人自由组合使编号之和为n。输出满足规则的所有可能的组合。要求组合内部编号升序输出,组合之间无顺序要求。
    输入描述:
    
    输入数据为以空格分隔的两个整数k和n
    
    
    
    输出描述:
    
    每行输出一个可能的编号组合,组合内部各个编号以空格分隔升序输出。若无满足规则的组合,则输出None
    
    示例1
    输入
    
    3 15
    
    输出
    
    1 5 9
    1 6 8
    2 4 9
    2 5 8
    2 6 7
    3 4 8
    3 5 7
    4 5 6
    

    解析

    #include<iostream>
    #include<math.h>
    
    #include <vector>
    #include <string>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <map>
    #include <unordered_map>
    #include <set>
    #include <unordered_set>
    
    #include <algorithm>
    #include <functional>
    #include <numeric> //accmulate
    
    #include <iterator> //ostream_iterator
    #include <fstream>
    #include <iomanip>  //setprecision() setw()
    using namespace std;
    
    //#define cin infile //一定不能再oj系统中,有错,导致超时等!!!
    //C++文件输入
    ifstream infile("in.txt", ifstream::in);  
    
    #include <limits>
    #define INT_MIN     (-2147483647 - 1) /* minimum (signed) int value */
    #define INT_MAX       2147483647    /* maximum (signed) int value */
    
    
    #if 1
    
    bool flag = false;
    
    void combination(vector<int> src, int i, int m, vector<int> &res, vector<vector<int>> &vecs,int target)
    {
    	if (i >= src.size() && m != 0)
    	{
    		return;
    	}
    	if (m == 0) //递归终止条件,个数
    	{
    		if (accumulate(res.begin(), res.end(), 0) == target)
    		{
    			flag = true;
    			copy(res.begin(), res.end(), ostream_iterator<int>(cout, " "));
    			cout << endl;
    		}
    		return;
    	}
    	//选择该元素
    	res.push_back(src[i]);
    	combination(src, i + 1, m - 1, res, vecs,target);
    	res.pop_back();
    	//不选该元素
    	combination(src, i + 1, m, res, vecs,target);
    
    	return;
    }
    
    int main()
    {
    	int a[9] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    
    	int m, n;
    	cin >> m >> n; //C(9,m) ;sum()=n
    	vector<int> input(a,a+9);
    	
    	vector<vector<int>> vecs;
    	vector<int> vec;
    	combination(input, 0, m, vec, vecs,n); ////C(n,m)
    
    	if (!flag)
    	{
    		cout << "None" << endl;
    	}
    
    	return 0;
    }
    
    
    #endif
    
    #if 1
    
    void PrintCombination(int *a, int n, int sum, vector<int>& vec)
    {	//a为输入数组,n为数组长度,sum为待查找的和,vec用于保存查找到的组合
    	if (sum==0)
    	{
    		vector<int>::iterator iter=vec.begin();
    		for (;iter!=vec.end();iter++)
    		{
    			cout<<*iter<<" ";
    		}
    		cout<<endl;
    		return;
    	}
    	else if(sum<0 || n<=0)
    		return;
    	vec.push_back(a[0]);//a[0]即*a,注指针a是变化的,每次指向后一个
    	PrintCombination(a+1,n-1,sum-a[0],vec);
    	vec.pop_back();
    
    	while(*a == *(a+1) && a < a+n) //跳过重复的数字  
    		a++; 
    	PrintCombination(a+1,n-1,sum,vec);
    }
    
    void main()
    {
    	int a[8]={8,3,6,5,7,2,4,1};
    	cout<<"原来的数组:";
    	copy(a, a + 8, ostream_iterator<int>(cout, " "));
    
    	sort(a,a+8);
    	cout<<"排序后数组:";
    	copy(a, a + 8, ostream_iterator<int>(cout, " "));
    	cout<<"-----------------------------"<<endl;
    
    	vector<int> vec;
    	int sum=10;
    	cout<<"和为"<<sum<<"的组合如下:"<<endl;
    	PrintCombination(a,8,sum,vec);
    
    	return;
    }
    
    
    #endif
    

    问题2:求从n个数组任意选取一个元素的所有组合

    求从n个数组任意选取一个元素的所有组合,对于这个问题,我们在直观上感觉很容易,但是用程序实现时则发现用for循环解决不了问题,因为n是随意的。
    在这里,我们用递归的思想,对于数据[1, 3, 4]; [2, 5]; [6, 7];
    

    问题3:打靶问题。一个射击运动员打靶,靶一共有10环,连开10 枪打中90环的可能性有多少?

    • 思路:这道题的思路与字符串的组合很像,用递归解决。一次射击有11种可能,命中1环至10环,或脱靶。
    • 参考代码
    //函数功能 : 求解number次打中sum环的种数  
    //函数参数 : number为打靶次数,sum为需要命中的环数,result用来保存中间结果,total记录种数   
    //返回值 :   无  
    void ShootProblem_Solution1(int number, int sum, vector<int> &result, int *total)  
    {  
        if(sum < 0 || number * 10 < sum) //加number * 10 < sum非常重要,它可以减少大量的递归,类似剪枝操作  
            return;  
        if(number == 1) //最后一枪  
        {  
            if(sum <= 10) //如果剩余环数小于10,只要最后一枪打sum环就可以了  
            {  
                for(unsigned i = 0; i < result.size(); i++)  
                    cout<<result[i]<<' ';  
                cout<<sum<<endl;  
                (*total)++;  
                return;  
            }  
            else  
                return;  
        }  
        for(unsigned i = 0; i <= 10; i++) //命中0-10环  
        {  
            result.push_back(i);  
            ShootProblem_Solution1(number-1, sum-i, result, total); //针对剩余环数递归求解  
            result.pop_back();  
        }  
    }  
    
  • 相关阅读:
    2019-9-10做题记录
    2019-9-9做题记录
    【HAOI2008】硬币购物
    【SCOI2010】生成字符串
    第18讲——ActiveX控件
    第20讲 HOOK和数据库编程
    第19讲——动态链接库
    2016-5-22 百度之星第三题--瞬间移动
    2016-4-25 完美世界-实习--小萌的包裹
    第3章 拍摄UFO——单一职责原则
  • 原文地址:https://www.cnblogs.com/ranjiewen/p/8669690.html
Copyright © 2020-2023  润新知