#2019122600027 递归五题

目录

1 全排列

2 01背包

3 自然数拆分

4 页码统计

5 汉诺塔

1 全排列

生成从\(1\)\(n\)的全排列

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int a[25];
bool vis[25];
int n;
int ans=0; 
void f(int x){
	if(x==n+1){
		ans++;
			for(int i=1;i<=n;i++){
				printf("%5d",a[i]);
			}
			printf("\n");
		return;
	}
	for(int i=1;i<=n;i++)
	{
		if(vis[i]==1) continue;
		bool q=1;
		if(q){
			vis[i]=1;
			a[x]=i;
			f(x+1);
			vis[i]=0;
		}
		
	}
	return ;
}
int main( ){
	scanf("%d",&n);
	f(1);
	printf("%d",ans); //...
	return 0;
} 

2 01背包问题

设一背包可容纳物品最大质量为\(M\),现有\(n\)件物品,质量是\(m_i(i\in [1,n],i\in N)\),要从这些物品中挑选若干件,使得质量之和恰好是\(K\),询问能否做到.

题解

\(knap(M,n)\)表示寻找的问题。
(1)先取最后一个物品\(m_n\)放入背包,如果\(m_n=M\),则return true.
(2)若\(m_n<M\),则\(M-m_n<0\),如果还有可选物品。即为\(n>1\),考虑\(knap(M-m_n,n-1)\)是否有解,如果有就return true.否则\(knap(M,n)\)转化为\(knap(M,n-1)\),即放弃最后一个物品,在前\((n-1)\)个物品内考虑问题.
(3)若\(m_n>M\),则第\(n\)件物品不能装入包中,这时如果还有可选物品,即\(n>1\),那么\(knap(M,n)\)转化为\(knap(m,n-1)\)

bool knap(int m,int n){
	if(m[n]==m) return true;
	else if(m[n]<m){
		if(n>1){
			if(knap(m-m[n],n-1)) return true;
			else return knap(m,n-1);
		}
		else return false;
	}
	else{
		if(n>1) return knap(m,n-1);
		else return false; 
	}
} 

3 自然数拆分

任何一个大于\(1\)的自然数\(n\),总可以拆分成若干小于\(n\)的自然数之和,求出\(n\)的所有拆分.

题解

用数组\(a\)储存完成\(n\)的一种拆分,不完全归纳法的分析可知当\(n=7\)时,按照\(a[1]\)分类,有\(a[1]=1,a[1]=2,...,a[1]=\dfrac{n}{2}\),共\(\dfrac{n}{2}\)大类拆分。在每一类拆分时,\(a[1]=i,a[2]=n-i\),从\(x=2\),继续拆分从\(a[x]\)开始,\(a[x]\)能否拆分取决于\(\dfrac{a[x]}{2}\)是否大于等于\(a[x-1]\)。递归过程的参数\(t\)指向要拆分的数\(a[x]\)

#include <cstdio>
#include <algorithm>
using namespace std;
void dfs(int t){
	int i,j,k;
	printf("%d=%d",n,a[1]);
	for(i=2;i<=t;i++){
		printf("+%d",a[i]);
	}
	printf("\n");
	j=t;k=a[j];
	for(i=a[j-1];i<=k/2;i++){
		a[j]=i;
		a[j+1]=k-i;
	}
}
int main(){
	int i,j,k;
	scanf("%d",&n);
	for(i=1;i<=n/2;i++){
		a[1]=i;
		a[2]=n-i;
		dfs(2);
	}

4 页码统计

一本书的页码共\(N\)页,页码从\(1\)开始。请你求出全部页码中用了多少个\(0,1,2,...,9\),其中不含前导\(0\),即页码只能是\(5\),而不是\(0005\).\((N\leq 10^9)\)

题解

可以从连续数字本身的规律出发来进行统计,这样速度比较快,先不考虑多余的\(0\)的情况,假设从\(0000-9999\),这一万个连续的数字,\(0\)\(9\)用到的次数都是相同的,一万个四位数,\(0\)\(9\)这十个数字共用了\(40000\)次,每个数字使用了\(4000\)次。

进一步推广,考虑所有\(n\)位数情况,从\(n\)\(0\)\(n\)\(9\),共\(10n\)\(n\)位数,\(0\)\(9\)十个数字平均使用,每个数字共用了\(n*10^{n-1}\)

有了这样的规律后,可以从高位向低位进行统计,最后再减去多余的\(0\)的个数。

\(n=3657\)为例;(用\(count\)数组来存放\(0\)\(9\)各个数字的使用次数)

最高位(千位)为3,从0千、1千到2千,000~999重复了3次,

posted @ 2019-12-26 19:53  刘子闻  阅读(134)  评论(1)    收藏  举报