C++ | 枚举与尺取法

组合

在n个中随机选m个

模板

//组合(在n个中随机选m个) 
#include <bits/stdc++.h>
using namespace std;

int n;
int m;
vector<int>chosen;

void calc(int x)  //当前处理到第x个数 
{
	//如果已经选了m个数 | 剩下的数全部选了也达不到m个 
	if(chosen.size()>m || chosen.size()+(n-x+1)<m)
		return;  //剪枝
	//全部数字都遍历完了 
	if(x==n+1)
	{
		for(int i=0;i<chosen.size();i++)
			cout<<chosen[i];
		cout<<endl;
		return;
	} 
	
	chosen.push_back(x); //选择当前数 
	calc(x+1); //处理下一个(递归) 
	chosen.pop_back();  //不选择当前数
	calc(x+1); //递归处理下一个 
}

int main()
{
	cin>>n>>m;
	calc(1);
}

排列

STL库函数:next_permutation()

功能:从当前的排列顺序开始,逐个输出更大的全排列,并把新的排列放在原来的空间里

返回值:是否有下一个排列组合

注意:排列的范围是 [ first , last ) 

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

int main()
{
	string s="bca";
	sort(s.begin(),s.end());  //字符串内部排序,得到最小的全排列
	//因为一调用next_permutation()字符串顺序就会变,所以先do一次 
	do{
		cout<<s<<endl;
	}while(next_permutation(s.begin(),s.end()));
	return 0;
}

 模板

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

int n;
int order[20];  //全排列 
bool chosen[20];  //记录当前位置的有没有被选择过 

void calc(int k) //第k个位置 
{
	if(k==n+1)
	{
		for(int i=1;i<=n;i++)
		{
			cout<<order[i];
		}
		cout<<endl;
		return;
	}
	
	for(int i=1;i<=n;i++)
	{
		//如果i已经被选择过了,跳过 
		if(chosen[i])
			continue;
		//选 
		chosen[i]=1;
		order[k]=i;
		calc(k+1);
		//不选
		chosen[i]=0;
	}
}

int main()
{
	cin>>n;
	calc(1);
}

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

int main()
{
	string s,olds;
	cin>>s;
	olds=s; //记录最初的串
	int cnt=0;
	sort(s.begin(),s.end());
	
	do{
		if(s==olds){
			cout<<cnt<<endl;
			break;
		}
		cnt++;
	}while(next_permutation(s.begin(),s.end()));
	return 0;
}
 lanqiaoOJ-572
#include <bits/stdc++.h>
using namespace std;

int main()
{
	int n,m;
	cin>>n>>m;
	int a[10000]={0};
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	
	for(int i=0;i<m;i++)
	{
		next_permutation(a,a+n);
	}
	
	int i=0;
	for(;i<n-1;i++){
		cout<<a[i]<<" ";
	}
	cout<<a[i];
	
	return 0;
}

子集

用二进制的概念进行对照,子集正好对应了二进制。例如n=3的集合{0,1,2}的子集和二进制数的对应关系是:

子集元素011,022,02,12,1,0
二进制数000001010011100101110111

 模板

//输出n个数的所有子集 
#include <bits/stdc++.h>
using namespace std;

int a[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14};

void print_subset(int n)
{
	for(int i=0;i<(1<<n);i++)
	{
		//i:0~2^n,每个i的二进制数对应一个子集
		
		for(int j=0;j<n;j++) //打印i的二进制数中所有的1对应的数 
		{
			if(i&(1<<j))  //从i的最低位开始,检查每一位,如果是1,打印
			/*
				n=3的情况下 
				j=0 001
				j=1 010
				j=2 100
			*/ 
				cout<<a[j];	
		} 
		cout<<endl;
	}
}
int main()
{
	int n=3;
	print_subset(n);
}

尺取法

同向(快慢指针)

lanqiao美丽的区间

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

int main()
{
	int n,s; cin>>n>>s;
	int a[100010]={0};
	for(int i=0;i<n;i++) cin>>a[i];
	
	int ans=1e8;  //存一个很大的数 
	int sum=0;
	
	//尺取法
	/*
		i在前,j在后
		i一直往前探,直到sum>s
		sum>s之后,先记录长度,再移动j,缩短区间长度,直到sum<s 
	*/ 
	for(int i=0,j=0;i<n;){
		if(sum<s){
			sum+=a[i];
			i++;
		}
		else{
			ans=min(i-j,ans);
			sum-=a[j]; //缩短区间长度 
			j++;
		}
	}
	if(ans==1e8) cout<<0;
	else cout<<ans;
	return 0;
}

反向

lanqiao回文数判定、找指定和的整数对

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值