深搜

这篇博客详细介绍了如何使用递归算法解决全排列、组合等数学问题,包括青藤oj上的多个题目,如全排列问题(#10049)、组合输出(#10277)、自然数和分解(#10119)以及数的划分问题(#160)。通过递归思路,博主阐述了解决这些问题的关键步骤,并提供了相应的代码实现。

青藤oj #10049. 全排列问题

题目描述

输出自然数 1 到n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式

n(1≤n<9)

输出格式

由 1~n 组成的所有不重复的数字序列,每行一个序列。注意,每个数前面输出4个空格,包括第一个数。

思路

用递归每一个数都试一遍,如果没用过就标记为1,如果用过就下一个;
用s存下每一深度记下的数,当深度大于位数时,输出s;
return,从上一步继续往下推;

代码

#include<bits/stdc++.h>
using namespace std;
int a[1000]={0},s[1000];
int n;
void dfs(int deep)
{
	if(deep==n+1)
	{
		for(int i=1;i<=n;i++)
		  cout<<"    "<<s[i];
		cout<<endl;
		return;
	}
	for(int i=1;i<=n;i++)
	{
		if(a[i]==1)
		  continue;
		a[i]=1;
		s[deep]=i;
		dfs(deep+1);
		a[i]=0;
	}
	return;
}
int main()
{
	cin>>n;
	dfs(1);
	return 0;
 } 

青藤oj #10277. 组合的输出

题目描述

排列与组合是常用的数学方法,其中组合就是从 n个元素中抽出 r个元素(不分顺序且 r<=n),我们可以简单地将n 个元素理解为自然数1 ,2 ,… ,n ,从中任取 r个数。现要求你用递归的方法输出所有组合。

输入格式

一行两个自然数n 、r (1<n<21 ,1<=r<=n )

输出格式

所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素前面包含一个空格(包括第一个元素)

思路

这题和上一题差不多,就是要考虑一个重复的问题;
我的方法是在每一次循环结束后,也就是这一深度每个数都试过后,就将上一深度+1到n之间的数归0,重新枚举;

代码

#include<bits/stdc++.h>
using namespace std;
int s[10000],ans[10000];
int n,r,x;
void dfs(int deep)
{
	if(deep==r+1)
	{
		for(int i=1;i<=r;i++)
		  cout<<" "<<ans[i];
		cout<<endl;
		return;
	}
	for(int i=1;i<=n;i++)
	{
		int x=i;
		if(s[i]==1)
		  continue;
		s[i]=1;
		ans[deep]=i;
		dfs(deep+1);
	}
	for(int i=ans[deep-1]+1;i<=n;i++)
	  s[i]=0;
	
}
int main()
{
	cin>>n>>r;
	dfs(1);
 } 

青藤oj #10119. 自然数和分解

题目描述

把自然数N分解为若干个大于 0 自然数之和,输出方案数。

输入格式

N,(1≤n≤50)

输出格式

方案数

思路

用x累计,每次都判断是否等于n;如果等于就s+1,return;
如果没到n那就从r(上一次循环所加的数)开始往下枚举;
如果x加上i小于或等于n的,x就加上i,将i赋值给r(下一层枚举时用);
循环完以后,减掉r(i也行);
最后输出s;

代码

#include<bits/stdc++.h>
using namespace std;
int n,s=0,x=0;
void dfs(int r)
{
	if(x==n)
	{
		s++;
		return;
	}
	for(int i=r;i>=1;i--)
	{
		if(x+i>n) continue;
		x+=i;
		r=i;
		dfs(r);
		x-=r;
	}
	return;
}
int main()
{
	cin>>n;
	dfs(n);
	cout<<s;
} 

青藤oj #160. 数的划分

题目描述

将整数n 分成k份,且每份不能为空,任意两份不能相同(不考虑顺序)。

例如:n=7,k=3下面三种分法被认为是相同的。

1,1,5; 1,5,1; 5,1,1;

问有多少种不同的分法。

输入格式

输入 n和k .

输出格式

方案数

思路

和上题相似,只是在s++时多判断一个条件,长度是否达到k;
(一开始超时,还加了快读快些。后来才知道是因为当deep>k+1,x<n时,还在继续递归,加上判断就好了)

代码

#include<bits/stdc++.h>
using namespace std;
int n,s=0,x=0,k;
inline int read()
{
	int x=0;char c=getchar();
	while (c<'0'||c>'9') c=getchar();
	while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x;
}
inline void write(int x)
{
    if(x<0){
    	putchar('-');
		x=-x;
	}
    if(x>9) 
		write(x/10);
    putchar(x%10+'0');
}
void dfs(int r,int deep)
{
	if(x==n&&deep==k+1)
	{
		s++;
		return;
	}
	if(deep==k+1) return ;
	for(int i=r;i>=1;i--)
	{
		if(x+i>n) continue;
		x+=i;
		r=i;
		dfs(r,deep+1);
		x-=r;
	}
	return;
}
int main()
{
	n=read();
	k=read();
	dfs(n,1);
	write(s);
} 

青藤oj

题目描述

输入格式

输出格式

思路

代码


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值