【算法】递归与分治

本文分享了三个有趣的算法题解析:计算阶乘末尾0的个数,生成螺旋方阵,以及寻找数组中第k小的数。文章详细介绍了算法原理和实现代码,适合算法初学者和竞赛选手参考。

期末加油冲!记录一下做过的题目(๑′ᴗ‵๑)

阶乘末尾0的个数

输入格式:

输入有若干行。第一行上有一个整数m,指明接下来的数字的个数。然后是m行,每一行包含一个确定的正整数n,1<=n<=1000000000。

输出格式:

对输入行中的每一个数据n,输出一行,其内容是n!中末尾0的个数。

int trailingZeroes(int n){
    int cnt=0;
    if(n<5) return 0; //n<5阶乘末尾没有0!
    while(n){ //需要注意这个循环的终止条件
        cnt+=(n/=5); //每5就加一个0
    }
    return cnt;
}

螺旋方阵

输入格式:

输入在一行中给出一个正整数N(<10)。

输出格式:

输出N×N的螺旋方阵。每行N个数字,每个数字占3位。

#include<iostream>
const int N=10;

int main(){
	int n;
	int arr[N][N]={0};
	scanf("%d",&n);
	arr[0][0]=1; //最左上角填1 
	int total=n*n; //总共可以填进去的个数
	int x=0,y=0,c=1; //c代表当前填的数字
	
	while(c!=total) { //终止条件 
	//!ans[][]表示当前位置是否被填入 
	 	while(y+1<n&&!arr[x][y+1]) //从左向右 
	 		arr[x][++y]=++c;
	 	while(x+1<n&&!arr[x+1][y]) //从上到下 
	 		arr[++x][y]=++c; 
	 	while(y-1>=0&&!arr[x][y-1]) //从右向左 注意这里要取到0! 
	 		arr[x][--y]=++c;
	 	while(x-1>=0&&!arr[x-1][y]) //从下到上 
	 		arr[--x][y]=++c; 	
	} 
	
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			printf("%3d",arr[i][j]);
		}
		printf("\n");
	}
} 

找第k小的数

输入格式:

输入有两行: 第一行是n和k,0<k<=n<=10000 第二行是n个整数

输出格式:

输出第k小的数

/*据a[left]~a[right]中的某个元素x(如a[left])
对a[left]~a[right]进行划分,划分后的x所在位置的左段全小于等于x,右段全大于等于x,
同时利用x所在的位置还可以计算出x是这批数据按升非降序排列的第几个数。*/
int partition(int a[],int left,int right){
	int temp=a[left]; //哨兵 
	while(left<right){ //终止条件 
		while(left<right&&a[right]>=temp){
			right--;
		}
		a[left]=a[right];
		
		while(left<right&&a[left]<=temp){ //要加上left<right 要取等号 
			left++;
		}
		a[right]=a[left];
	}
	a[left]=temp;
	return left;
}

//通过调用partition函数获得划分点,判断划分点是否第k小,若不是,递归调用find函数继续在左段或右段查找。
int find(int a[],int left,int right,int k){
	int p=partition(a,left,right);
	if(p<k-1){ //划分点p小于k,往右 
		return find(a,p+1,right,k);
	}
	else if(p>k-1){ //划分点大于k,往左 
		return find(a,left,p-1,k);
	}
	else{
		printf("%d",a[k-1]);
	}
	return 0;
}

int main(){
	int n,k,a[1000];
	scanf("%d %d",&n,&k);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
	}
	find(a,0,n-1,k);
	return 0;
}

一、循环日程赛

【问题描述】设有n=2k个选手要进行网球循环赛,要求设计一个满足以下要求的比赛日程表:
(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能赛一次;
(3)循环赛在n-1天之内结束。

int main(){
	int Table[M][M];
	int k,total;
	scanf("%d",&k);
	total=1<<k; //n=2^k;  
	//printf("%d",total); 
	
	int n=2; //n=2为初始 
	int i,j,m,tmp;
	
	Table[1][1]=1; //初始化表格 
	Table[1][2]=2;
	Table[2][1]=2;
	Table[2][2]=1;
	
	for(m=1;m<=k;m++){
		tmp=n; //要放到循环里面 而且是tmp=nnnnn!!!
		 
		n*=2; //放到循环里面
		 
		for(i=1+tmp;i<=n;i++) //左下角
			for(j=1;j<=tmp;j++)
				Table[i][j]=Table[i-tmp][j]+tmp;
		for(i=1;i<=tmp;i++) // 右上角 = 左下角
			for(j=1+tmp;j<=n;j++)
				Table[i][j]=Table[i+tmp][j-tmp]; //这里注意是Table[i+tmp][j-tmp] 
		for(i=tmp+1;i<=n;i++) //右下角 = 左上角 
			for(j=tmp+1;j<=n;j++)
				Table[i][j]=Table[i-tmp][j-tmp];
	}
	
	for(int i=1;i<=total;i++){
		for(int j=1;j<=total;j++){
			printf("%3d",Table[i][j]);
		}
		printf("\n");
	}
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值