排列数 组合数辨析

排列数

解空间大小为2^n,选与不选

void dfs(int x){
	if(x == n+1){//所有数全部排列完成 
		//output
		return;
	} 
	for(int i = 0 ;i < n; i++){
		if(vis[i] == 0){//没有遍历过 
			vis[i] = 1;
			a[x] = i;//存储该数
			dfs(x+1); //位置加1  
			vis[i] = 0;//回溯 
		}
	}
	//可以使用vector存储
	/*for(int i = 1 ; i <= n ;i++){
		if(!vis[i]){
			vis[i] = 1;
			p.push_back(i);
			dfs(x+1);
			vis[i] = 0 ;
			p.pop_back();//一定要弹出哦 
		}
	} 
	*/
}

dfs(x+1);//注意这个地方只是位置增加,但是for循环里面i还是从1开始,还是一个一个看有没有访问过,没访问的往里面加元素,

组合数问题/排列数

问题规模n!,两两组合

void dfs(int start,int res){
	if(组成数的个数达到要求){// 
		//output
		return;
	} 

	for(int i = start ; i <= n ;i++){
		if(!vis[i]){
			vis[i] = 1;
			p.push_back(i);
			dfs(start+1,res+1);
		}
	} 
	
}

此时for 循环从i = start 开始,且start +1 ,保证不重复 

 实例

选数问题

给定若干个正整数a0、a0 、…、an-1 ,从中选出若干数,使它们的和恰好为k

要求找选择元素个数最少的解。如果有多个最优解,输出字典序最小的。

输入格式:

输入有两行,第一行给出2个正整数n,k,用空格分隔。第二行是用空格分隔的n个整数。

输出格式:

输出有两行,第一行从小到大输出选择的元素,第二行输出元素的个数。

输入样例:

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

5 9
1 1 4 5 7

输出样例:

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

4 5
2

注意该问题的限制条件

子集和 字典序列最小(包含的数个数最少的)

//组合数从第二个开始选择
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int a[10000];
int n,k;
int vis[1000];
vector<int> p;
vector<int> c;
int minn = 100;//定义最少元素个数
void dfs(int start,int sum,int size){
    if(sum == k){
        if(minn>size){
            minn = size;//记录最小元素元素个数
            c.clear();
            for(int i = 0 ;i<size;i++)
                c.push_back(p[i]);
        }
    }
    if(start >= n) return ;
    if(sum > k) return ;
    for(int i = start ;i < n;i++){
        if(!vis[a[i]]){
            vis[a[i]] = 1;
            p.push_back(a[i]);
            dfs(start+1,sum+a[i],size+1);//组合问题
            vis[a[i]] = 0;
            p.pop_back();
        }
    }
}
int main(){
    cin>>n>>k;
    for(int i = 0 ;i < n;i++)
        cin>>a[i];
    sort(a,a+n);
    dfs(0,0,0);
    for(int i = 0; i < c.size();i++){
        cout<<c[i];
        if(i!=c.size()-1){
            cout<<" ";
        }
        else cout<<endl;
    }
    cout<<c.size();
    return 0;
}

 

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值