第四届蓝桥杯大赛个人赛省赛(软件类)C/C++ 大学A组

本博客所有蓝桥杯相关代码皆有JAVA实现
试题A:高斯日记

 大数学家高斯有个好习惯:无论如何都要记日记。 

   他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210 

   后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢? 

   高斯出生于:1777430日。 
    
   在高斯发现的一个重要定理的日记上标注着:5343,因此可算出那天是:17911215日。 

   高斯获得博士学位的那天日记上标着:8113    

   请你算出高斯获得博士学位的年月日。 

提交答案的格式是:yyyy-mm-dd, 例如:1980-03-21 

这里大家只需要注意一个地方就好了,就是高斯出生的那一天是第一天,这个可能会导致大家结果与答案差1哦,因为我就是这样wa了一发

package lan4A_C;
 // 出生的第一天算为一天  高斯日记
public class TestA {
	static int dx[] = new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};
	static boolean check(int x){
		if(x%400 == 0 || (x%4 == 0 && x%100 != 0))
			return true;
		return false;
	}
	public static void main(String[] args) {
		int y = 1777;
		int m = 4;
		int d = 30;
		for(int i = 1;i <= 8113-1;i++){
			d++;
			if(m == 2 && check(y)){
				if(d > 29){
					d = 1;
					m++;
				}
			}
			else{
				if(d > dx[m]){
					d = 1;
					m++;
				}
			}
			if(m > 12){
				m = 1;
				y++;
			}
		}
		System.out.println(y+" "+m+" "+d);
	}
}

试题B:排它平方数

小明正看着 203879 这个数字发呆。 

   原来,203879 * 203879 = 41566646641 

   这有什么神奇呢?仔细观察,203879 是个6位数,并且它的每个数位上的数字都是不同的,并且它平方后的所有数位上都不出现组成它自身的数字。 

   具有这样特点的6位数还有一个,请你找出它! 

   再归纳一下筛选要求: 
   1. 6位正整数 
   2. 每个数位上的数字不同 
   3. 其平方数的每个数位不含原数字的任何组成数位 

答案是一个6位的正整数。 

这个题目意思很简单,无非就是要我们枚举6位数判断一下即可
(1)这里我使用get1函数将这个6位数分解在a数组中,方便判断是否与乘积后出现重复。
(2)使用get2函数将乘积后的结果分位存放在b数组中,理由与上面相同,
另外用个变量cnt计数看结果有多少位数

package lan4A_C;
import java.util.*;
public class TestB {
	static long a[] = new long[6]; // 存6位数
	static long b[] = new long[20];;
	static int cnt = 0;
	static void get1(long x){
		int k = 5;
		while(x != 0){
			long t = x%10;
			a[k] = t;
			x /= 10;
			k--;
		}
	}
	static void get2(long x){
		cnt = 0;
		while(x != 0){
			long t = x%10;
			b[cnt++] = t;
			x /= 10;
		}
	}
	public static void main(String[] args) {
		for(long i = 100000;i < 1000000;i++){
			get1(i);
			TreeSet<Long> set = new TreeSet<Long>();
			for(int j = 0;j < 6;j++)
				set.add(a[j]);
			if(set.size() == 6){ // 6位数第不相同
				long s = i*i;
				get2(s);
				int j = 0;
				boolean ok = false;
				for(j = 0;j < cnt;j++){ // 判断每个数是否重复
					int k = 0;
					if(ok)
						break;
					while(k < 6){
						if(b[j] == a[k]){
							ok = true;  // 是否出现了重复
							break;
						}
						k++;
					}
				}
				if(!ok){
					System.out.println(i);
				}
			}
		}
	}
}

试题C:振兴中华

小明参加了学校的趣味运动会,其中的一个项目是:跳格子。 

   地上画着一些格子,每个格子里写一个字,如下所示:(也可参见p1.jpg) 

   比赛时,先站在左上角的写着“从”字的格子里,可以横向或纵向跳到相邻的格子里,但不能跳到对角的格子或其它位置。一直要跳到“华”字结束。 


   要求跳过的路线刚好构成“从我做起振兴中华”这句话。 

   请你帮助小明算一算他一共有多少种可能的跳跃路线呢? 

这个题说实话。。我一看这图片这么小,我还想手算,然后发现结果真的有点多,所以建议还是编程实现以下,结果还真不小。
(1)很简单的dfs思路,我们可以把数组从我做起,振兴中华看成数字12345678存在数组中,然后就好办了

package lan4A_C;

public class TestC {
	static int map[][] = new int[][]{
		{1,2,3,4,5},
		{2,3,4,5,6},
		{3,4,5,6,7},
		{4,5,6,7,8}
	};
	static int ans = 0;
	static int dx[] = new int[]{1,-1,0,0};
	static int dy[] = new int[]{0,0,1,-1};
	static void dfs(int x,int y){
		if(map[x][y] == 8){
			ans ++;
			return;
		}
		for(int i = 0;i < 4;i++){
			int xx = x+dx[i];
			int yy = y+dy[i];
			if(xx>=0&&xx<4&&yy>=0&&yy<5 && map[xx][yy]-map[x][y] == 1)
				dfs(xx,yy);
		}
	}
	public static void main(String[] args) {
		dfs(0,0);
		System.out.println(ans);
	}
}

试题D:颠倒的价牌

小李的店里专卖其它店中下架的样品电视机,可称为:样品电视专卖店。 

   其标价都是4位数字(即千元不等)。 

   小李为了标价清晰、方便,使用了预制的类似数码管的标价签,只要用颜色笔涂数字就可以了(参见p1.jpg)。 

   这种价牌有个特点,对一些数字,倒过来看也是合理的数字。如:1 2 5 6 8 9 0 都可以。这样一来,如果牌子挂倒了,有可能完全变成了另一个价格,比如:1958 倒着挂就是:8561,差了几千元啊!!  

   当然,多数情况不能倒读,比如,1110 就不能倒过来,因为0不能作为开始数字。 

   有一天,悲剧终于发生了。某个店员不小心把店里的某两个价格牌给挂倒了。并且这两个价格牌的电视机都卖出去了! 

   庆幸的是价格出入不大,其中一个价牌赔了2百多,另一个价牌却赚了8百多,综合起来,反而多赚了558元。 

   请根据这些信息计算:赔钱的那个价牌正确的价格应该是多少? 

题意就是说有一些数字是可以颠倒的,4个数字放在一起成为一个牌子,如果这个牌子可以颠倒,说明这4个数字都可以颠倒,然后我们根据这个在去判断一下就好了

package lan4A_C;

public class TestD { // 11 22 55 69 88 96 00
	static int a[] = new int[]{0,1,2,-1,-1,5,6,-1,8,9}; // 不能颠倒设为-1
	static boolean get(int x){ // 是否满足颠倒
		while(x != 0){
			int t = x%10;
			if(a[t] == -1)
				return false;
			x /= 10;
		}
		return true;
	}
	static int last(int x){ // 颠倒后的结果
		int sum = 0;
		while(x != 0){
			sum *= 10;
			int t = x%10;
			if(t == 6)
				sum += 9;
			else if(t == 9)
				sum += 6;
			else
				sum += t;
			x /= 10;
		}
		return sum;
	}
	public static void main(String[] args) {
		for(int i = 1000;i < 10000;i++)
			for(int j = 1000;j < 10000;j++)
				if(get(i) && get(j)){
					int t1 = i - last(i);
					int t2 = last(j) - j;
					if(t1>200 && t1<300 && t2>800 && t2<900 && t2-t1==558){
						System.out.println(i+" "+j);
						return;
					}
				}
	}
}

试题G:错误票据

某涉密单位下发了某种票据,并要在年终全部收回。 

   每张票据有唯一的ID号。全年所有票据的ID号是连续的,但ID的开始数码是随机选定的。 

   因为工作人员疏忽,在录入ID号的时候发生了一处错误,造成了某个ID断号,另外一个ID重号。 

   你的任务是通过编程,找出断号的ID和重号的ID。 

   假设断号不可能发生在最大和最小号。

这个题思路很清晰,就是找到没有的编号跟重复的编号即可,很清晰的排序思路。
(1)这个题的读入是给了一个行数,但是没有给每行有多少个数,我们这里可以用每行读入,读入后然后用split函数将每个数字都分开就好了split("\D+")表示将除了数字以外的字符作为分隔符全部去掉,然后存放在String数组中
(2)这个题的数字范围不大于100000,这里我就用计数排序来实现了因为最近刚刚学了计数排序,故想装下B 关于计数排序,如果有不懂的,可以先看下别人的博客- -,我估计几天后也会发,发了会贴在此题下面。
(3)还是简单解释一下,计数排序也称为桶排序,就是把数字的最大范围设为数组的最大上限,然后每读入一个数就把这个数存在相对应的数组下标中,比如读入3,就存在a[3]中,读入98888就存在a[98888]中,次方法只适用于数字不是很大的情况下。

package lan4A_C;
import java.util.*;
public class TestG {
	static int a[] = new int[100100];
	static int n;
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		sc.nextLine();
		for(int i = 0;i < n;i++){
			String s[] = sc.nextLine().split("\\D+");
			for(int j = 0;j < s.length;j++)
				a[Integer.valueOf(s[j])]++;
		}
		int key[] = new int[2]; // 存结果
		Arrays.fill(key, 0);
		for(int i = 0;i < 100002;i++){
			if(a[i] == 0 && i-1>=0 && a[i-1]!=0 && a[i+1]!=0)
				key[0] = i;
			if(a[i] == 2)
				key[1] = i;
			if(key[0] != 0 && key[1] != 0)
				break;
		}
		System.out.println(key[0]+" "+key[1]);
	}
}

试题H:买不到的数目

小明开了一家糖果店。他别出心裁:把水果糖包成4颗一包和7颗一包的两种。糖果不能拆包卖。 
小朋友来买糖的时候,他就用这两种包装来组合。当然有些糖果数目是无法组合出来的,比如要买 10 颗糖。 
你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是17。大于17的任何数字都可以用47组合出来。 
本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。

害- - 这个题真是心累,我就不写回答了,大家看这个大佬的玄学证明过程吧
玄学证明
总是就是结果就是 a*b-a-b

package lan4A_C;
import java.util.*;
public class TestH {
	static int a[] = new int[1000000];
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int t = sc.nextInt();
		int k = sc.nextInt();
		System.out.println(t*k-k-t);
	}
}

试题I:剪格子

   我们沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是60。 

   本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。 
   如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。    
   如果无法分割,则输出 0

说实话,我真的不认为这个题会给直接使用dfs的代码过,因为dfs只能一个方向搜索,在回溯的时候不可能产出2个方向的区域,但是我刷题的时候还是使用了dfs。。。因为本人太菜,写不出完美代码
上述给出一个例子
5 2 3
6 4 5
8 9 18
这个题题意要的是如果可以分的话,我们要选有左上格子的,那么很明显,我们选出来的可以是5 2 6 8 9 但是dfs不可能搜出来这种结果的。。本人太菜,欢迎大佬指出错误
最后还是发一下代码

package lan4A_C;
import java.io.*;
import java.util.Arrays;
public class TestI {
	static int n,m;
	static int map[][];
	static boolean vis[][];
	static int ans = 0;
	static int sum = 0;
	static int xx[] = new int[]{1,-1,0,0};
	static int yy[] = new int[]{0,0,1,-1};
	static void dfs(int x,int y,int cnt,int k){
		if(cnt == (sum>>1)){
			ans = k;
			return;
		}
		if(cnt > (sum>>1))
			return;
		for(int i = 0;i < 4;i++){
			int dx = x + xx[i];
			int dy = y + yy[i];
			if(dx>=0 && dx<n && dy>=0 && dy<m && !vis[dx][dy]){
				vis[dx][dy] = true;
				dfs(dx,dy,cnt+map[dx][dy],k+1);
				vis[dx][dy] = false;
			}
		}
	}
	public static void main(String[] args) throws IOException{
		StreamTokenizer re = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		PrintWriter pr = new PrintWriter(new OutputStreamWriter(System.out));
		re.nextToken(); m = (int)re.nval;
		re.nextToken(); n = (int)re.nval;
		map = new int[n][m];
		vis = new boolean[n][m];
		for(int i = 0;i < n;i++){
			Arrays.fill(vis[i], false);
			for(int j = 0;j < m;j++){
				re.nextToken();
				map[i][j] = (int)re.nval;
				sum += map[i][j];
			}
		}
		for(int i = 0;i < n;i++){
			for(int j = 0;j < m;j++){
				for(int k = 0;k < n;k++)
					Arrays.fill(vis[k], false);
				vis[i][j] = true;
				dfs(i,j,map[i][j],1);
				if(ans != 0){
					pr.println(ans);
					pr.flush();
					return;
				}
			}
		}
	}
}

试题J:大臣的旅费
这个题另外写了一篇博客,大家有需要的可以跳转下网页
大臣的旅费

发布了32 篇原创文章 · 获赞 5 · 访问量 862

猜你喜欢

转载自blog.csdn.net/shizhuba/article/details/104916188