PTA|口袋取球 子集树

口袋取球

在一个口袋里有x种不同编号的小球(编号从1开始到x),现允许取y次,问取次的结果有哪些可能的情况,为方便区分,要求对取出的小球按编号从大到小进行排序。

输入格式:

在一行中输入两个整数,以空格隔开,分别代表x, 和y。

输出格式:

对每一组可能,在一行中输出这组对应的小球的编号,编号之间以空格分隔,每一行必须以一个回车结束。

输入样例:

在这里给出一组输入。例如:

3 2

输出样例:

在这里给出相应的输出。例如:

3 2 
3 1 
2 1 

这个问题可以使用全排列的类似做法,只是仔细读题会发现,2和1相当于1和2,所以只能取1个就可以了,不用回退到所有 前面已经选择的数。

第一种解法:

组合数,位置标记法

#include<iostream>
using namespace std;
int n,m;//n为有多少个小球,m是取多少次
int res[10000];
void dfs(int x,int n){
    if(x == m+1){
        for(int i = 1;i <= m;i++){
            cout<<res[i]<<" ";
        }
        cout<<endl;
        return;
    }
    for(int i = n;i>=1;i--){
        res[x] = i;
        dfs(x+1,n-1);
    }
}
int main(){
    cin>>n>>m;
    dfs(1,n);//位置,取得次数
    return 0;
}

注意:dfs(x+1,i-1)为dfs( 位置,数字)//这个数字是减少的,不会再从头开始选择

第二种解法:

子集树,参考01背包问题选择与不选择的判断

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6+10; 
int n,m;//小球编号 和 取球次数
vector<int> p;//存放临时解 
void dfs(int x,int count){
	if(count == n){
		if(p.size() ==2){
			for(int i = 0 ; i < 2;i++)
			cout<<p[i]<<" ";
			cout<<endl;
		}
	}
	p.push_back(x);
	dfs(x-1,count+1);
	p.pop_back();
	dfs(x-1,count+1);
}
int main(){
	cin>>n>>m;
	dfs(n,0);//降序选择小球 
}

猜你喜欢

转载自blog.csdn.net/Brittney27/article/details/134935663