用递归解决蓝桥杯的一道排列问题

题目大概是这样的:有七对数,{1,2,3,4,5,6,7},利用这七对数排列成一个14位数,要求是每对数中间相隔的位数是这一对数的值,如34563,一对3中间隔着三个数,其他类似,举一个用例25623745361417就是满足要求的一个排列。现在要求编程实现一个以74开头的一个排列。

思考如下:以74开头的一个排列,就是74****4*7*****,*号是要求的。首先我们不要考虑以74开头来思考算法,寻找一般性再说。7对数,14位数,我们先从这14个数中选一个数作为第一位,接着从剩下的13个数选择一个作为第二位数,以此类推。这就像我们数学中的排列组合问题了 ,总共的排列数为,不考虑重复的情况。其实,每一种就是从n个数中选一个数,都是同样的操作,这就想到用递归来解决这道题了。这里要考虑一个问题,但从中选择一个数m时,我们就要给这个数做标记,表示这个数已经选择过了,下一位数就从剩下的数中选择,同时,还要考虑这次选择了数m,下次我们就选择数n了,这时就要把之前给m做标记还原,表示未选择。我采取的方法是,如果这个数选择了,就把它置为0。


初始代码如下:

public class NumTest {

	public static void main(String[] args) {
		int[] num={1,1,2,2,3,3,4,4,5,5,6,6,7,7};//选择的数
		int[] test=new int[14];		//装载要产生的14位数
		run(num,num.length,test,0);	//递归函数
	}
	//length为固定值,为数组的长度,from为test数组的下标
	public static void run(int[] num,int length,int[] test,int from){
		if(from==test.length){
			testNum(test);	//检验规则函数
			return;
		}
		
		for(int i=0;i<length;i++){					
		<span style="white-space:pre">	</span>if(num[i]!=0 ){
			<span style="white-space:pre">	</span>test[from]=num[i];
			<span style="white-space:pre">	</span>num[i]=0;
			<span style="white-space:pre">	</span>run(num, length, test, from+1);<span style="white-space:pre">	</span>//递归下一位
			<span style="white-space:pre">	</span>num[i]=test[from];
			}
			
		}
				
	}
	
	public static void testNum(int[] test){
		int length=test.length;
		int sub=test.length-1;
		int[] tempT=new int[14];//tempT数组用来判断这个数是否判断过
		for(int i=0;i<length;i++){
			if(tempT[i]==-1)   //-1表示这对数已判断过
				continue;
			else{
				int temp=test[i];//要间隔多少个数
				int pos=temp+i+1;  //求出相对应的位置
				if(pos>sub)	//如果这个数越界,表示此排列不满足要求
					return;
				if(temp!=test[pos])//相对应的位置不是一对数,不满足要求
					return;
				tempT[pos]=-1; 
			}
		}
		for(int k:test)
			System.out.print(k);
		System.out.println();		
	}

}
这段代码不要测试,因为没半个小时是运行不出来的,可能还要更久,你算算总的排列数就知道有多大了。下面我们考虑以74开头的排列,这是代码在原来的基础上修改就简单了。如下:

public class NumTest {

	public static void main(String[] args) {
		int[] num={1,1,2,2,3,3,5,5,6,6};//选择的数,排除4,7
		int[] test=new int[14];		//装载要产生的14位数
		test[0]=7;
		test[1]=4;
		test[6]=4;
		test[8]=7;
		run(num,num.length,test,0);	//递归函数
	}
	//length为固定值,为数组的长度,from为test数组的下标
	public static void run(int[] num,int length,int[] test,int from){
		if(from==test.length){
			testNum(test);	//检验规则函数
			return;
		}
		if(from==0 || from==1 || from==6 || from==8){<span style="white-space:pre">	</span>//如果遇到4,7的位置,直接递归下一位
			run(num, length, test, from+1);
		}else{
			for(int i=0;i<length;i++){					
				if(num[i]!=0){
					test[from]=num[i];
					num[i]=0;
					run(num, length, test, from+1);<span style="white-space:pre">	</span>//递归下一位
					num[i]=test[from];
				}
			}
		}
		
	}
	public static void testNum(int[] test){
		int length=test.length;
		int sub=test.length-1;
		int[] tempT=new int[14];//tempT数组用来判断这个数是否判断过
		for(int i=0;i<length;i++){
			if(tempT[i]==-1)  //-1表示这对数已判断过
				continue;
			else{
				int temp=test[i];//要间隔多少个数
				int pos=temp+i+1;  //求出相对应的位置
				if(pos>sub)	//如果这个数越界,表示此排列不满足要求
					return;
				if(temp!=test[pos])//相对应的位置不是一对数,不满足要求
					return;
				tempT[pos]=-1; 
			}
		}
		for(int k:test)
			System.out.print(k);
		System.out.println();		
	}

}
这段代码你可以拿来测试了,运行后,你会发现输出了重复的排列数,原因在哪里呢?问题就在这七对数上,因为它是一对数,所以这次你选择了1,下一次还有一次选择了1,这样就导致重复了。解决办法是用一个数来记录这次选择的数,然后判断下一次选择的数是否和上一次相同,若相同则选择下一个数。最终代码如下:

public class NumTest {

	public static void main(String[] args) {
		int[] num={1,1,2,2,3,3,5,5,6,6};//选择的数
		int[] test=new int[14];		//装载要产生的14位数
		test[0]=7;
		test[1]=4;
		test[6]=4;
		test[8]=7;
		run(num,num.length,test,0);	//递归函数
	}
	//length为固定值,为数组的长度,from为test数组的下标
	public static void run(int[] num,int length,int[] test,int from){
		if(from==test.length){
			testNum(test);	//检验规则函数
			return;
		}
		if(from==0 || from==1 || from==6 || from==8){
			run(num, length, test, from+1);
		}else{
			int temp=0;
			for(int i=0;i<length;i++){					
				if(num[i]!=0 && num[i]!=temp){
					test[from]=num[i];
					num[i]=0;
					run(num, length, test, from+1);
					num[i]=test[from];
				}
				temp=num[i];
			}
		}
		
	}
	public static void testNum(int[] test){
		int length=test.length;
		int sub=test.length-1;
		int[] tempT=new int[14];//tempT数组用来判断这个数是否判断过
		for(int i=0;i<length;i++){
			if(tempT[i]==-1)  //-1表示这对数已判断过
				continue;
			else{
				int temp=test[i];//要间隔多少个数
				int pos=temp+i+1;  //求出相对应的位置
				if(pos>sub)	//如果这个数越界,表示此排列不满足要求
					return;
				if(temp!=test[pos])//相对应的位置不是一对数,不满足要求
					return;
				tempT[pos]=-1; 
			}
		}
		for(int k:test)
			System.out.print(k);
		System.out.println();		
	}

}

最终结果为74151643752362。

好了,终于写完了,不知道你看懂了没,可能我讲解的不是条理很清晰。如果有问题的,可以在下面留言,我会努力帮你解答。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值