突发奇想想用C解决高中排列组合问题

题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?

很简单的一道高中题目,用程序来也是很好实现的。话不多说,直接上代码。

#include<stdio.h>
 
int main()
{
    int i,j,k;
    printf("\n");
    for(i=1;i<5;i++) { // 以下为三重循环
        for(j=1;j<5;j++) {
            for (k=1;k<5;k++) { // 确保i、j、k三位互不相同
                if (i!=k&&i!=j&&j!=k) { 
                    printf("%d,%d,%d\n",i,j,k);
                }
            }
        }
    }
}

因为是三位数,而且四个数字还是连着的,所以只需要来一个三重循环,再把有相同数字的去掉就行。

那如果是一个六位数,十位数,显然循环套循环就不太方便了。

而且,如果数字是2、4、6、8,它甚至都不能用上述循环。

这就是我下面要解决的问题。既然基本思路就是循环套循环,那么能不能整一个n重循环呢?答案是肯定的,大家可以看看我的上一篇文章找零问题的一种遍历算法——“时钟模型”找零问题的一种遍历算法——“时钟模型”。里面提到了一种遍历算法,类似于时钟,它可用于连续数字的n重循环。当然大家就会问,万一不是连续数字呢?这其实很好解决,只需要一点映射的概念,比如有一个数组{2, 4, 6, 8},虽说它的元素不是连续的。但是它的下标永远是连续的呀。

有了上面的分析,我们就可以开始敲代码了。

首先得知道“时钟模型”

while(1){
        b[n-1]--;
        for(j=n-1;j>=1;j--){
            if(b[j]==-1){
                b[j-1]--;
                b[j]=m[j];//m[n-1]是存储b[n-1]初值的数组,此处未写出
            }
        }
        if(b[0]==-1) break;
	}

 其次就是如何将下标和数组元素对应,并输出。很简单,将一个元素都是顺序排列的数组代入上述代码,这就是普通的带有顺序的排列组合。再将带有目标数字的一个数组,以这样array1[array2[i]]的形式输出即可。附带代码便于理解。

void fun1()
{
    int array1[4] = {2, 4, 6, 8};
    fun2(array1);
}

void fun2(int array1[], n, m)
{   
    int array2[m],mm[m];
    for(int i=0;i<m;i++) array2[i] = mm[i] = n-1;
    while(1){
        for(int i=0;i<n;i++){
            printf("%d",array1[array2[i]]);
        }
        printf("\n");
        array2[n-1]--;
        for(j=n-1;j>=1;j--){
            if(array2[j]==-1){
                array2[j-1]--;
                array2[j]=mm[j];
            }
        }
        if(array2[0]==-1) break;
    }
}

写到这,差不多基本原理都写完了。 其作为一道经典的高中题目,有时会有许多限制,比如组成的数字要从大到小,或者从小到大,二话不说直接上代码。

#include<stdio.h>

void onput1(int b[], int n, int ptr[], int m, int key);
void onput2(int b[], int n, int ptr[], int m, int key);
int dif(int array[], int n);//判断数组是否有重复元素
int mima(int array[], int n);//判断元素是否大于0 
void input();

int dif(int array[], int n)
{
	int ii,jj,md=0;
	for(ii=0;ii<n-1;ii++){
		for(jj=ii+1;jj<n;jj++){
			if(array[ii]==array[jj]) md=1;
		}
		if(md==1) break;
	}
	
	return !md;
}

int mima(int array[], int n)
{
	int md=1;
	for(int ii=0;ii<n;ii++){
		if(array[ii]>9 || array<0) md=0;
	}
	
	return md;
}

void onput1(int b[], int n, int ptr[], int m, int key)
{
	int mm[n],nn[n],sum=0;
	for(int k=0;k<n;k++){
		mm[k]=b[k];
	}
	while(1){
		for(int i=0;i<n;i++){
			nn[i]=ptr[b[i]];
		}
		if((key==0 ? dif(nn, n)) : 1 && ptr[b[0]]!=0){
			for(int i=0;i<n;i++){
	        	printf("%d",ptr[b[i]]);
			}
			printf("\n");
			sum++;
		}
        b[n-1]--;
        for(int j=n;j>=1;j--){
            if(b[j]==-1){
                b[j-1]--;
                b[j]=mm[j];
            }
        }
        if(b[0]==-1) break;
	}
	printf("总共有%d种情况:",sum);
}

void onput2(int b[], int n, int ptr[], int m, int key)
{
	int mm[n],sum=0,result,l;
	for(int k=0;k<n;k++){
		mm[k]=b[k];
	}
	while(1){
		if(key==1){
			for(l=0;l<n-1;l++){
				if(ptr[b[l]]>=ptr[b[l+1]]) break;
			}
			if(l==n-1 && ptr[b[0]]!=0){
				for(int i=0;i<n;i++){
		        	printf("%d",ptr[b[i]]);
				}
				sum++;
				printf("\n");
			}
		}else if(key==2){
			for(l=0;l<n-1;l++){
				if(ptr[b[l]]<=ptr[b[l+1]]) break;
			}
			if(l==n-1 && ptr[b[0]]!=0){
				for(int i=0;i<n;i++){
		        	printf("%d",ptr[b[i]]);
				}
				sum++;
				printf("\n");
			}
		}
        b[n-1]--;
        for(int j=n;j>=1;j--){
            if(b[j]==-1){
                b[j-1]--;
                b[j]=mm[j];
            }
        }
        if(b[0]==-1) break;
	}
	printf("总共有%d种情况:",sum);
}

void input()
{
	int n,m,*ptr,key=0;
	printf("请输入需要数字的个数:");
	scanf("%d",&n);
	int array[n];
	printf("分别是:");
	for(int i=0;i<n;i++){
		scanf("%d",&array[i]);
	}
	printf("要组成几位数:");
	scanf("%d",&m);
	int b[m]; 
	ptr=array;
	for(int i=0;i<m;i++){
		b[i]=n-1;
	}
	if(dif(array, n) && mima(array, n)){
		printf("从小到大排列输入1\n从大到小输入2\n无重复数字输入0\n需要重复数字输入3\n-->");
		scanf("%d",&key);
		if(key==1){
			onput2(b, m, ptr, n, key);
		}else if(key==2){
			onput2(b, m, ptr, n, key);
		}else{
			onput1(b, m, ptr, n, key);
		}
	}else{
		printf("[ERROR]数据输入错误,请重新输入\n");
		input(); 
	} 
}

main()
{
	input();
}

还有我运行的结果

  

 

 好了,我的分享到此结束了。如果你感兴趣的话,不如自己动手继续修饰这段代码,让它能够解决更多的关于高中排列组合的问题。

  • 21
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
使用飞思卡尔电机和s3010舵机,可以实现许多有趣的项目和创意。对于使用超声波控制舵机的程序,我在一个下午的时间里编写了以下代码。 首先,我导入了所需的库和模块。我使用了Arduino的软件和它的舵机库,这样可以简化编程过程并提供链式函数来控制舵机的角度。我还使用了超声波模块来测量距离。 然后,我初始化了舵机和超声波模块的引脚。我将超声波的Trig引脚连接到Arduino的数字引脚,将Echo引脚连接到Arduino的另一个数字引脚。我还将舵机的信号线连接到Arduino的数字引脚。 接下来,我编写了一个函数来测量超声波的距离。这个函数使用超声波模块发送一个短脉冲,然后通过计算返回超声波返回的时间与物体之间的距离。 然后,我编写了另一个函数来控制舵机的角度。这个函数接受一个角度作为参数,并将舵机旋转到相应的位置。 在主循环中,我使用超声波函数来测量到最近物体的距离。然后,如果距离小于某个阈值,我将调用舵机控制函数来旋转舵机到一定角度。这样,当有物体靠近时,舵机会自动旋转。 最后,我上传了代码到Arduino开发板,并将飞思卡尔电机和s3010舵机连接到正确的引脚。接下来,我打开了水龙头和超声波模块之间的距离。如果有物体靠近超声波模块,舵机会自动旋转到一定角度,打开水龙头。 这个程序可以通过多次试验和调整来优化,以达到准确控制舵机角度的目的。通过这个程序,我实现了使用超声波控制舵机的想法,并且能够自动打开水龙头,实现了更方便的操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值