码迷,mamicode.com
首页 > 其他好文 > 详细

第四届蓝桥杯编程题:带分数 (转)

时间:2015-04-27 18:17:39      阅读:3299      评论:0      收藏:0      [点我收藏+]

标签:

 100 可以表示为带分数的形式:100 = 3 + 69258 / 714

    还可以表示为:100 = 82 + 3546 / 197

    注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。

    类似这样的带分数,100 有 11 种表示法。

题目要求:
从标准输入读入一个正整数N (N<1000*1000)
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!

例如:
用户输入:
100
程序输出:
11


再例如:
用户输入:
105
程序输出:
6


资源约定:
峰值内存消耗(含虚拟机) < 64M
CPU消耗  < 3000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。


所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。

注意:主类的名字必须是:Main,否则按无效代码处理。

 

分析:这道题初看起来第一感觉就是用暴力破解应该可以搞定,但是时间复杂度应该会相当可观,仔细观察,会发现这道题无非是全排列的一种运用,把等式定义为:

N=A+B/C ,则ABC组合在一起就是1到9的一个全排列,所以可以把问题转换成对于一个9位数的数字,如何将其划分为A、B、C三部分,使得其满足N=A+B/C(隐含条件:

B%C==0),对于一个9位数可以这样考虑:A是不可能大于N的,所以A的位数只可能是从1位到和N相同位数这个范围,确定了A的位数之后,剩下的就是B和C的总位数,

B数字的开始位置即A数字的下一位,C数字的最后一位就是整个9位数的最后一位,那如何确定B的结束位置呢?

这里有个小技巧,可以大大减少可能性的判断:

假设A的结束位置为 aEnd,则aEnd+1~9就是B和C的位置,在这个位置范围内,B最少占据了一半的数字,否则B/C就不能整除了,所以可以从aEnd+1~9的中间位置开始

确定B的结束位置,这时候可以从中间位置开始向后确定B的结束位置,一直到8的位置,确定了B的结束位置,则A、B、C三个数字的具体值就都可以确定了,判断是否符

合等式N=A+B/C,符合则输出。

以上确定B的结束位置的方法其实不怎么好,因为还是会浪费一些时间(自己模拟下就知道了),不过已经可以在规定的时间内得出答案了。

这里再介绍一种确定B结束位置的方法,可以让性能再提高一些:

 

观察等式:N=A+B/C,可以转换成==》B=(N-A)*C,N和A确定了(先确定A的结束位置后,再来确定B的结束位置的),C的最后一个数字确定了(整个9位数最后一位),即可以确定B最后一个数字了(这里将其定义为BL),这样可以从以上的aEnd+1~9的中间位置开始找,直到8,当数字为BL时,则判读是否符合等式:N=A+B/C,可以想想,其实这种等于BL的位置至多有一次(因为数字1到9不能重复出现),所以第一次找到和BL匹配的数字的时候就不用再往后找了。用这种方法,提高的性能还是非常可观的!

思想其实挺简单,想不到打成字这么麻烦,将就着看吧,以下为java版的代码:

 

  1. import java.util.Scanner;  
  2.   
  3. public class ys_09 {  
  4.       
  5.     public static void main(String[] args) {  
  6.         //将等式定义为:N=A+B/C  
  7.         Scanner scanner=new Scanner(System.in);  
  8.         N=scanner.nextInt();  
  9.         long start=System.currentTimeMillis();  
  10.         int[] s=new int[]{1,2,3,4,5,6,7,8,9};  
  11.         NLength=(N+"").length();  
  12.         allRange(s, 0, s.length-1);  
  13.         long end=System.currentTimeMillis();          
  14.         System.out.println("耗时:"+(end-start)+" ms");  
  15.         System.out.println("总数为:"+kinds+" 种");    
  16.     }  
  17.     public static int N;  
  18.     public static int NLength;//N数字的长度  
  19.     public static int kinds;  
  20.     public static void process(int[] s){  
  21.         String str="";  
  22.         for(int i=0;i<9;i++) str+=s[i];  
  23.         int A,B,C,NMA,BC,BMCL,BLastNumber;  
  24.         //A的位数  
  25.         for(int i=1;i<=NLength;i++){  
  26.               
  27.             /* 
  28.             //方法1 
  29.             A=Integer.valueOf(str.substring(0, i)); 
  30.             NMA=N-A;//N减去A的值 
  31.             if(NMA<=0)return; 
  32.             BC=9-i;//B和C还有多少为可用 
  33.             BMCL=(NMA+"").length();//B/C的长度  
  34.             //确定的B的结束为止 
  35.             for(int j=i+BC/2;j<=8;j++){//可以优化这里 
  36.                 B=Integer.valueOf(str.substring(i,j)); 
  37.                 C=Integer.valueOf(str.substring(j,9)); 
  38.                 if(B%C==0&&B/C==NMA){ 
  39.                     kinds++; 
  40.                     System.out.println(N+"="+A+"+"+B+"/"+C); 
  41.                 } 
  42.             } 
  43.             */  
  44.               
  45.             //方法2  
  46.             A=Integer.valueOf(str.substring(0, i));  
  47.             NMA=N-A;   
  48.             if(NMA<=0)return;  
  49.             BC=9-i;//B和C总共多少位  
  50.   
  51.             BLastNumber=(NMA*s[8])%10;//B最后的数字  
  52.             //j为B最后一个数字的位置  
  53.             //B最少占有B和C全部数字的一半,否则B/C不可能为整数  
  54.             for(int j=i+BC/2-1;j<=7;j++){  
  55.                 //找到符合的位置  
  56.                 if(s[j]==BLastNumber){  
  57.                     B=Integer.valueOf(str.substring(i,j+1));  
  58.                     C=Integer.valueOf(str.substring(j+1,9));  
  59.                     if(B%C==0&&B/C==NMA){  
  60.                         kinds++;  
  61.                         System.out.println(N+"="+A+"+"+B+"/"+C);  
  62.                     }  
  63.                     //符合要求的位置只可能出现一次  
  64.                     break;  
  65.                 }  
  66.             }  
  67.         }  
  68.     }  
  69.     public static void swap(int[] s,int a,int b){  
  70.         if(a==b)return;  
  71.         int tmp=s[a];  
  72.         s[a]=s[b];  
  73.         s[b]=tmp;  
  74.     }  
  75.     //全排列  
  76.     public static void allRange(int[] s,int k,int m){  
  77.         if(k==m){  
  78.             process(s);  
  79.             return;  
  80.         }  
  81.         else{  
  82.             for(int i=k;i<=m;i++){  
  83.                 swap(s,k,i);  
  84.                 allRange(s, k+1, m);  
  85.                 swap(s,k,i);  
  86.             }  
  87.         }  
  88.     }  
  89. }  
import java.util.Scanner;

public class ys_09 {
	
	public static void main(String[] args) {
		//将等式定义为:N=A+B/C
		Scanner scanner=new Scanner(System.in);
		N=scanner.nextInt();
		long start=System.currentTimeMillis();
		int[] s=new int[]{1,2,3,4,5,6,7,8,9};
		NLength=(N+"").length();
		allRange(s, 0, s.length-1);
		long end=System.currentTimeMillis();		
		System.out.println("耗时:"+(end-start)+" ms");
		System.out.println("总数为:"+kinds+" 种");	
	}
	public static int N;
	public static int NLength;//N数字的长度
	public static int kinds;
	public static void process(int[] s){
		String str="";
        for(int i=0;i<9;i++) str+=s[i];
		int A,B,C,NMA,BC,BMCL,BLastNumber;
		//A的位数
		for(int i=1;i<=NLength;i++){
			
			/*
			//方法1
			A=Integer.valueOf(str.substring(0, i));
			NMA=N-A;//N减去A的值
			if(NMA<=0)return;
			BC=9-i;//B和C还有多少为可用
			BMCL=(NMA+"").length();//B/C的长度 
			//确定的B的结束为止
			for(int j=i+BC/2;j<=8;j++){//可以优化这里
				B=Integer.valueOf(str.substring(i,j));
				C=Integer.valueOf(str.substring(j,9));
				if(B%C==0&&B/C==NMA){
					kinds++;
					System.out.println(N+"="+A+"+"+B+"/"+C);
				}
			}
			*/
			
			//方法2
			A=Integer.valueOf(str.substring(0, i));
			NMA=N-A; 
			if(NMA<=0)return;
			BC=9-i;//B和C总共多少位

			BLastNumber=(NMA*s[8])%10;//B最后的数字
			//j为B最后一个数字的位置
			//B最少占有B和C全部数字的一半,否则B/C不可能为整数
			for(int j=i+BC/2-1;j<=7;j++){
				//找到符合的位置
				if(s[j]==BLastNumber){
					B=Integer.valueOf(str.substring(i,j+1));
					C=Integer.valueOf(str.substring(j+1,9));
					if(B%C==0&&B/C==NMA){
						kinds++;
						System.out.println(N+"="+A+"+"+B+"/"+C);
					}
					//符合要求的位置只可能出现一次
					break;
				}
			}
		}
	}
	public static void swap(int[] s,int a,int b){
		if(a==b)return;
		int tmp=s[a];
		s[a]=s[b];
		s[b]=tmp;
	}
	//全排列
	public static void allRange(int[] s,int k,int m){
		if(k==m){
			process(s);
			return;
		}
		else{
			for(int i=k;i<=m;i++){
				swap(s,k,i);
				allRange(s, k+1, m);
				swap(s,k,i);
			}
		}
	}
}

 

 

输入:100

输出:

 

    1. 100=3+69258/714  
    2. 100=82+3546/197  
    3. 100=81+5643/297  
    4. 100=81+7524/396  
    5. 100=94+1578/263  
    6. 100=96+2148/537  
    7. 100=96+1428/357  
    8. 100=96+1752/438  
    9. 100=91+5742/638  
    10. 100=91+5823/647  
    11. 100=91+7524/836  
    12. 耗时:554 ms  
    13. 总数为:11 种  

第四届蓝桥杯编程题:带分数 (转)

标签:

原文地址:http://www.cnblogs.com/lujinyu/p/4460816.html

(1)
(4)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!