蓝桥杯真题练习(2017节选)

迷宫
X星球的一处迷宫游乐场建在某个小山坡上。
它是由10x10相互连通的小房间组成的。

房间的地板上写着一个很大的字母。
我们假设玩家是面朝上坡的方向站立,则:
L表示走到左边的房间,
R表示走到右边的房间,
U表示走到上坡方向的房间,
D表示走到下坡方向的房间。

X星球的居民有点懒,不愿意费力思考。
他们更喜欢玩运气类的游戏。这个游戏也是如此!

开始的时候,直升机把100名玩家放入一个个小房间内。
玩家一定要按照地上的字母移动。

迷宫地图如下:
UDDLUULRUL
UURLLLRRRU
RRUURLDLRD
RUDDDDUUUU
URUDLLRRUU
DURLRLDLRL
ULLURLLRDU
RDLULLRDDD
UUDDUDUDLL
ULRDLUURRR
请你计算一下,最后,有多少玩家会走出迷宫?
而不是在里边兜圈子。

请提交该整数,表示走出迷宫的玩家数目,不要填写任何多余的内容。

如果你还没明白游戏规则,可以参看一个简化的4x4迷宫的解说图:
p1.png
在这里插入图片描述
思路:dfs+标记深搜

public class Main {

	static String[] data = new String[10];
	static int[][] vis = new int[10][10];
	static int count = 0;

	public static void main(String[] args) {
		data[0] = "UDDLUULRUL";
		data[1] = "UURLLLRRRU";
		data[2] = "RRUURLDLRD";
		data[3] = "RUDDDDUUUU";
		data[4] = "URUDLLRRUU";
		data[5] = "DURLRLDLRL";
		data[6] = "ULLURLLRDU";
		data[7] = "RDLULLRDDD";
		data[8] = "UUDDUDUDLL";
		data[9] = "ULRDLUURRR";
		for (int i = 0; i < 10; i++) {
			for (int j = 0; j < 10; j++) {
				clear();
				boolean res = dfs(i, j);
				if (res) {
					count++;
				}
			}
		}
		System.out.println(count);
	}

	public static void clear() {
		for (int i = 0; i < 10; i++) {
			for (int j = 0; j < 10; j++) {
				vis[i][j] = 0;
			}
		}

	}

	public static boolean dfs(int i, int j) {
		if (i < 0 || j < 0 || i > 9 || j > 9) {
			return true;
		}
		if (vis[i][j] == 1) {
			return false;
		}
		vis[i][j] = 1;
		switch (data[i].charAt(j)) {
		case 'U':
			return dfs(i - 1, j);
		case 'D':
			return dfs(i + 1, j);
		case 'L':
			return dfs(i, j - 1);
		case 'R':
			return dfs(i, j + 1);

		default:
			return false;
		}
	}
}

9数算式
观察如下的算式:

9213 x 85674 = 789314562

左边的乘数和被乘数正好用到了1~9的所有数字,每个1次。
而乘积恰好也是用到了1~9的所有数字,并且每个1次。

请你借助计算机的强大计算能力,找出满足如上要求的9数算式一共有多少个?

注意:

总数目包含题目给出的那个示例。
乘数和被乘数交换后作为同一方案来看待。

import java.util.HashSet;
import java.util.Set;

public class Main2 {

	static int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	static int res = 0;

	public static void main(String[] args) {

		dfs(0);
		System.out.println(res / 2);
	}

	public static void dfs(int i) {
		if (i == 9) {
			for (int j = 1; j < 9; j++) {
				int x1 = a2j(0, j);
				int x2 = a2j(j, 9);
				int x = x1 * x2;
				if (check(x)) {

					res++;
				}
			}
		}
		for (int j = i; j < 9; j++) {
			int t = a[i];
			a[i] = a[j];
			a[j] = t;
			dfs(i + 1);
			t = a[i];
			a[i] = a[j];
			a[j] = t;
		}

	}

	public static boolean check(int i) {
		String s = i + "";
		if (s.length() != 9 || s.indexOf('0') > -1)
			return false;
		Set<Character> set = new HashSet<>();
		for (int j = 0; j < s.length(); j++) {
			set.add(s.charAt(j));
		}
		return set.size() == 9;
	}

	public static int a2j(int i, int j) {
		int ans = 0;
		int p = 1;
		for (int k = j - 1; k >= i; k--) {
			ans += a[k] * p;
			p *= 10;
		}
		return ans;
	}

}

方格分割

6x6的方格,沿着格子的边线剪开成两部分。
要求这两部分的形状完全相同。

如图:p1.png, p2.png, p3.png 就是可行的分割法。

试计算:
包括这3种分法在内,一共有多少种不同的分割方法。
注意:旋转对称的属于同一种分割法。

请提交该整数,不要填写任何多余的内容或说明文字。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
思路:可以把中心点作为起点,利用dfs深搜,两个人走着完全对称的路径,若都能走到边界则总方案数加1,由于是中心对称图形,所以最终得到的结果除以4

public class Main3 {

	// 标记数组
	static int[][] vis = new int[7][7];
	// 方向数组
	static int[][] dir = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
	static int ans = 0;

	public static void main(String[] args) {
		// 中心点
		vis[3][3] = 1;
		// 从中心点出发
		dfs(3, 3);
		// 旋转的情况是一样的,需要除以4
		System.out.println(ans / 4);
	}

	public static void dfs(int x, int y) {
		// 走到边界
		if (x == 0 || y == 0 || x == 6 || y == 6) {
			ans++;
			return;
		}
		for (int i = 0; i < 4; i++) {
			int dx = x + dir[i][0];
			int dy = y + dir[i][1];

			if (vis[dx][dy] == 1)
				continue;
			// 标记走过
			vis[dx][dy] = 1;
			// 对称点
			vis[6 - dx][6 - dy] = 1;

			dfs(dx, dy);

			// 回溯
			vis[dx][dy] = 0;
			vis[6 - dx][6 - dy] = 0;
		}

	}
}

正则问题

考虑一种简单的正则表达式:
只由 x ( ) | 组成的正则表达式。
小明想求出这个正则表达式能接受的最长字符串的长度。

例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是: xxxxxx,长度是6。

输入

一个由x()|组成的正则表达式。输入长度不超过100,保证合法。

输出

这个正则表达式能接受的最长字符串的长度。

例如,
输入:
((xx|xxx)x|(x|xx))xx

程序应该输出:
6

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

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

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

import java.util.Scanner;

public class Main4 {

	static String s;
	static int pos = 0;// 指针
	static int len = 0;// 长度

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		s = sc.next();
		len = s.length();
		System.out.println(f());

	}

	public static int f() {
		int temp = 0;// 临时变量
		int m = 0;// 记录最大值
		while (pos < len) {
			if (s.charAt(pos) == '(') {
				pos++;
				// 递归
				temp += f();
			} else if (s.charAt(pos) == 'x') {
				pos++;
				temp++;
			} else if (s.charAt(pos) == '|') {
				pos++;
				m = Math.max(m, temp);
				temp = 0;
			} else if (s.charAt(pos) == ')') {
				pos++;
				m = Math.max(m, temp);
				return m;
			}
		}
		m = Math.max(m, temp);
		return m;
	}

}

包子凑数

小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有N种蒸笼,其中第i种蒸笼恰好能放Ai个包子。每种蒸笼都有非常多笼,可以认为是无限笼。

每当有顾客想买X个包子,卖包子的大叔就会迅速选出若干笼包子来,使得这若干笼中恰好一共有X个包子。比如一共有3种蒸笼,分别能放3、4和5个包子。当顾客想买11个包子时,大叔就会选2笼3个的再加1笼5个的(也可能选出1笼3个的再加2笼4个的)。

当然有时包子大叔无论如何也凑不出顾客想买的数量。比如一共有3种蒸笼,分别能放4、5和6个包子。而顾客想买7个包子时,大叔就凑不出来了。

小明想知道一共有多少种数目是包子大叔凑不出来的。

输入

第一行包含一个整数N。(1 <= N <= 100)
以下N行每行包含一个整数Ai。(1 <= Ai <= 100)

输出

一个整数代表答案。如果凑不出的数目有无限多个,输出INF。

例如,
输入:
2
4
5

程序应该输出:
6

再例如,
输入:
2
4
6

程序应该输出:
INF

样例解释:
对于样例1,凑不出的数目包括:1, 2, 3, 6, 7, 11。
对于样例2,所有奇数都凑不出来,所以有无限多个。

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

import java.util.Scanner;

public class Main5 {

	// f[i]表示是否能凑出i
	/*
	 * 欧几里得扩展公式不定方程系数互质时最大凑不出的值满足 x*y-x-y,这里是100*100-200
	 */
	static boolean[] f = new boolean[10000];
	static int g;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int[] a = new int[n + 1];
		f[0] = true;
		for (int i = 1; i <= n; i++) {
			a[i] = sc.nextInt();
			// 求最大公约数
			if (i == 1)
				g = a[i];
			else
				g = gcd(g, a[i]);

			// 完全背包的递推
			for (int j = 0; j < 10000 - a[i]; j++) {
				if (f[j]) {
					f[j + a[i]] = true;
				}
			}
		}
		// 系数不互质
		if (g != 1) {
			System.out.println("INF");
			return;
		}
		// 统计递推表里凑不出的个数
		int ans = 0;
		for (int i = 0; i < 10000; i++) {
			if (!f[i]) {
				ans++;
			}
		}
		System.out.println(ans);
	}

	public static int gcd(int a, int b) {
		if (b == 0)
			return a;
		return gcd(b, a % b);
	}
}

分巧克力

儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。

为了公平起见,小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:

1. 形状是正方形,边长是整数  
2. 大小相同  

例如一块6x5的巧克力可以切出6块2x2的巧克力或者2块3x3的巧克力。

当然小朋友们都希望得到的巧克力尽可能大,你能帮小Hi计算出最大的边长是多少么?

输入
第一行包含两个整数N和K。(1 <= N, K <= 100000)
以下N行每行包含两个整数Hi和Wi。(1 <= Hi, Wi <= 100000)
输入保证每位小朋友至少能获得一块1x1的巧克力。

输出
输出切出的正方形巧克力最大可能的边长。

样例输入:
2 10
6 5
5 6

样例输出:
2

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

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

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

import java.util.Scanner;

public class Main6 {

	static int n, k;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		k = sc.nextInt();
		int[] h = new int[n];
		int[] w = new int[n];
		for (int i = 0; i < n; i++) {
			h[i] = sc.nextInt();
			w[i] = sc.nextInt();
		}
		// 最小和最大边长
		int l = 1;
		int r = 100001;
		int ans = 0;
		while (l <= r) {
			int mid = l + ((r - l) >> 1);
			int cnt = 0;
			for (int i = 0; i < n; i++) {
				cnt += (h[i] / mid) * (w[i] / mid);
			}
			if (cnt >= k) {
				l = mid + 1;
				ans = mid;
			} else {
				r = mid - 1;
			}
		}
		System.out.println(ans);

	}
}

油漆面积

X星球的一批考古机器人正在一片废墟上考古。
该区域的地面坚硬如石、平整如镜。
管理人员为方便,建立了标准的直角坐标系。

每个机器人都各有特长、身怀绝技。它们感兴趣的内容也不相同。
经过各种测量,每个机器人都会报告一个或多个矩形区域,作为优先考古的区域。

矩形的表示格式为(x1,y1,x2,y2),代表矩形的两个对角点坐标。

为了醒目,总部要求对所有机器人选中的矩形区域涂黄色油漆。
小明并不需要当油漆工,只是他需要计算一下,一共要耗费多少油漆。

其实这也不难,只要算出所有矩形覆盖的区域一共有多大面积就可以了。
注意,各个矩形间可能重叠。

本题的输入为若干矩形,要求输出其覆盖的总面积。

输入格式:
第一行,一个整数n,表示有多少个矩形(1<=n<10000)
接下来的n行,每行有4个整数x1 y1 x2 y2,空格分开,表示矩形的两个对角顶点坐标。
(0<= x1,y1,x2,y2 <=10000)

输出格式:
一行一个整数,表示矩形覆盖的总面积。

例如,
输入:
3
1 5 10 10
3 1 20 20
2 7 15 17

程序应该输出:
340

再例如,
输入:
3
5 2 10 6
2 7 12 10
8 1 15 15

程序应该输出:
128

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

import java.util.Scanner;

public class Main7 {

	// 标记数组
	static boolean[][] vis = new boolean[10005][10005];

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();

		for (int i = 0; i < n; i++) {
			int x1 = sc.nextInt();
			int y1 = sc.nextInt();
			int x2 = sc.nextInt();
			int y2 = sc.nextInt();

			paint(x1, y1, x2, y2);
		}

		int sum = 0;
		for (int i = 0; i < 10005; i++) {
			for (int j = 0; j < 10005; j++) {
				if (vis[i][j]) {
					sum += 1;
				}
			}
		}
		System.out.println(sum);
	}

	public static void paint(int x1, int y1, int x2, int y2) {
		for (int i = x1; i < x2; i++) {
			for (int j = y1; j < y2; j++) {
				vis[i][j] = true;
			}
		}

	}

}

纸牌三角形

A,2,3,4,5,6,7,8,9 共9张纸牌排成一个正三角形(A按1计算)。要求每个边的和相等。
下图就是一种排法

在这里插入图片描述

这样的排法可能会有很多。

如果考虑旋转、镜像后相同的算同一种,一共有多少种不同的排法呢?

请你计算并提交该数字。

注意:需要提交的是一个整数,不要提交任何多余内容。

//旋转要除以3,镜像要除以2
public class Main8 {

	static int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	static int ans = 0;

	public static void main(String[] args) {
		f(0);
		System.out.println(ans / 6);
	}

	public static void f(int i) {
		if (i == a.length) {
			if (check(a)) {
				ans++;
			}
			return;
		}
		for (int j = i; j < a.length; j++) {
			int t = a[i];
			a[i] = a[j];
			a[j] = t;
			f(i + 1);
			t = a[i];
			a[i] = a[j];
			a[j] = t;
		}

	}

	public static boolean check(int[] a) {
		int a1 = a[0] + a[1] + a[3] + a[5];
		int a2 = a[0] + a[2] + a[4] + a[8];
		int a3 = a[5] + a[6] + a[7] + a[8];
		if (a1 == a2 && a2 == a3) {
			return true;
		}
		return false;
	}
}

标题:承压计算
 
X星球的高科技实验室中整齐地堆放着某批珍贵金属原料。
 
每块金属原料的外形、尺寸完全一致,但重量不同。
金属材料被严格地堆放成金字塔形。
 
                             7 
                            5 8 
                           7 8 8 
                          9 2 7 2 
                         8 1 4 9 1 
                        8 1 8 8 4 1 
                       7 9 6 1 4 5 4 
                      5 6 5 5 6 9 5 6 
                     5 5 4 7 9 3 5 5 1 
                    7 5 7 9 7 4 7 3 3 1 
                   4 6 4 5 5 8 8 3 2 4 3 
                  1 1 3 3 1 6 6 5 5 4 4 2 
                 9 9 9 2 1 9 1 9 2 9 5 7 9 
                4 3 3 7 7 9 3 6 1 3 8 8 3 7 
               3 6 8 1 5 3 9 5 8 3 8 1 8 3 3 
              8 3 2 3 3 5 5 8 5 4 2 8 6 7 6 9 
             8 1 8 1 8 4 6 2 2 1 7 9 4 2 3 3 4 
            2 8 4 2 2 9 9 2 8 3 4 9 6 3 9 4 6 9 
           7 9 7 4 9 7 6 6 2 8 9 4 1 8 1 7 2 1 6 
          9 2 8 6 4 2 7 9 5 4 1 2 5 1 7 3 9 8 3 3 
         5 2 1 6 7 9 3 2 8 9 5 5 6 6 6 2 1 8 7 9 9 
        6 7 1 8 8 7 5 3 6 5 4 7 3 4 6 7 8 1 3 2 7 4 
       2 2 6 3 5 3 4 9 2 4 5 7 6 6 3 2 7 2 4 8 5 5 4 
      7 4 4 5 8 3 3 8 1 8 6 3 2 1 6 2 6 4 6 3 8 2 9 6 
     1 2 4 1 3 3 5 3 4 9 6 3 8 6 5 9 1 5 3 2 6 8 8 5 3 
    2 2 7 9 3 3 2 8 6 9 8 4 4 9 5 8 2 6 3 4 8 4 9 3 8 8 
   7 7 7 9 7 5 2 7 9 2 5 1 9 2 6 5 3 9 3 5 7 3 5 4 2 8 9 
  7 7 6 6 8 7 5 5 8 2 4 7 7 4 7 2 6 9 2 1 8 2 9 8 5 7 3 6 
 5 9 4 5 5 7 5 5 6 3 5 3 9 5 8 9 5 4 1 2 6 1 4 3 5 3 2 4 1 
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X 
 
其中的数字代表金属块的重量(计量单位较大)。
最下一层的X代表30台极高精度的电子秤。
 
假设每块原料的重量都十分精确地平均落在下方的两个金属块上,
最后,所有的金属块的重量都严格精确地平分落在最底层的电子秤上。
电子秤的计量单位很小,所以显示的数字很大。
 
工作人员发现,其中读数最小的电子秤的示数为:2086458231
 
请你推算出:读数最大的电子秤的示数为多少?
 
注意:需要提交的是一个整数,不要填写任何多余的内容。
import java.util.Arrays;
import java.util.Scanner;

public class Main9 {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		long[][] a = new long[30][30];
		long f = (long) Math.pow(2, 30);
		for (int i = 0; i < 29; i++) {
			for (int j = 0; j <= i; j++) {
				a[i][j] = sc.nextLong();
				a[i][j] *= f;
			}
		}

		for (int i = 0; i < 29; i++) {
			for (int j = 0; j <= i; j++) {
				long tmp = a[i][j] / 2;
				a[i + 1][j] += tmp;
				a[i + 1][j + 1] += tmp;
			}
		}

		Arrays.sort(a[29]);
		System.out.println(a[29][0] / 2);
		System.out.println(a[29][29] / 2);
	}
}

日期问题

小明正在整理一批历史文献。这些历史文献中出现了很多日期。小明知道这些日期都在1960年1月1日至2059年12月31日。令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。

比如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。

给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?

输入

一个日期,格式是"AA/BB/CC"。 (0 <= A, B, C <= 9)

输入

输出若干个不相同的日期,每个日期一行,格式是"yyyy-MM-dd"。多个日期按从早到晚排列。

样例输入

02/03/04

样例输出

2002-03-04
2004-02-03
2004-03-02

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

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

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

public class Main10 {

	static String s;
	static String[] c;
	static Set<String> set = new TreeSet<>();

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		s = sc.next();
		int a = (s.charAt(0) - '0') * 10 + (s.charAt(1) - '0');
		int b = (s.charAt(3) - '0') * 10 + (s.charAt(4) - '0');
		int c = (s.charAt(6) - '0') * 10 + (s.charAt(7) - '0');
		check1(a, b, c);
		check1(c, a, b);
		check1(c, b, a);
		for (String t : set) {
			System.out.println(t);
		}
	}

	public static void check1(int a, int b, int c) {
		if (a >= 0 && a < 60) {
			a += 2000;
		} else if (a >= 60 && a <= 99) {
			a += 1900;
		} else
			return;

		if (b < 1 || b > 12) {
			return;
		}
		if (c < 1 || c > 31) {
			return;
		}
		switch (b) {
		case 2:
			if (isR(a)) {
				if (c > 29) {
					return;
				}
			} else {
				if (c > 28) {
					return;
				}
			}
			break;
		case 4:
		case 6:
		case 9:
		case 11:
			if (c > 30)
				return;
			break;
		default:
			break;
		}
		String s1 = "" + a;
		String s2 = "" + b;
		String s3 = "" + c;
		if (s2.length() == 1)
			s2 = "0" + s2;
		if (s3.length() == 1)
			s3 = "0" + s3;
		set.add(s1 + "-" + s2 + "-" + s3);
	}

	public static boolean isR(int a) {

		return (a % 4 == 0 && a % 100 != 0) || (a % 400 == 0);
	}

}

k倍区间

给定一个长度为N的数列,A1, A2, … AN,如果其中一段连续的子序列Ai, Ai+1, … Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间。

你能求出数列中总共有多少个K倍区间吗?

输入

第一行包含两个整数N和K。(1 <= N, K <= 100000)
以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)

输出

输出一个整数,代表K倍区间的数目。

例如,
输入:

5 2
1
2
3
4
5

程序应该输出:

6
利用前缀和

import java.util.Scanner;

public class Main11 {

	static int n, k;
	static int[] a;
	static int[] s;
	static long ans = 0;
	static int[] cnt = new int[1000001];

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		k = sc.nextInt();
		a = new int[n + 1];
		s = new int[n + 1];
		s[0] = 0;
		// 余数为0的前缀和有一个了
		cnt[0] = 1;
		for (int i = 1; i <= n; i++) {
			a[i] = sc.nextInt();
			// 求前缀和
			s[i] = s[i - 1] + a[i];
			// 求前缀和取模k的余数
			s[i] %= k;
			cnt[s[i]]++;
		}
		// 余数为0~k-1之间
		for (int i = 0; i < k; i++) {
			// 余数相等的前缀和中任意取两个
			ans += (long) cnt[i] * (cnt[i] - 1) / 2;
		}
		System.out.println(ans);
	}

}

Excel地址
题目描述
Excel单元格的地址表示很有趣,它使用字母来表示列号。
比如,
A表示第1列,
B表示第2列,
Z表示第26列,
AA表示第27列,
AB表示第28列,
BA表示第53列,

当然Excel的最大列号是有限度的,所以转换起来不难。
如果我们想把这种表示法一般化,可以把很大的数字转换为很长的字母序列呢?

本题目既是要求对输入的数字, 输出其对应的Excel地址表示方式。

例如,
输入:
26
则程序应该输出:
Z

再例如,
输入:
2054
则程序应该输出:
BZZ

我们约定,输入的整数范围[1,2147483647]

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

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

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

思路:利用进制转换的思想

import java.util.Scanner;

public class Main12 {

	static long n;
	// 记录余数
	static long[] ans = new long[100];

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextLong();
		int cnt = 0;// 余数个数
		while (n != 0) {
			// 特殊处理
			if (n % 26 == 0) {
				ans[cnt++] = 26;
				n = n / 26 - 1;
			} else {
				ans[cnt++] = n % 26;
				n /= 26;
			}
		}

		for (int i = cnt - 1; i >= 0; i--) {
			System.out.print((char) ('A' + ans[i] - 1));
		}
	}

}

拉马车
题目描述
小的时候,你玩过纸牌游戏吗?
有一种叫做“拉马车”的游戏,规则很简单,却很吸引小朋友。

其规则简述如下:
假设参加游戏的小朋友是A和B,游戏开始的时候,他们得到的随机的纸牌序列如下:
A方:[K, 8, X, K, A, 2, A, 9, 5, A]
B方:[2, 7, K, 5, J, 5, Q, 6, K, 4]

其中的X表示“10”,我们忽略了纸牌的花色。

从A方开始,A、B双方轮流出牌。

当轮到某一方出牌时,他从自己的纸牌队列的头部拿走一张,放到桌上,并且压在最上面一张纸牌上(如果有的话)。

此例中,游戏过程:
A出K,B出2,A出8,B出7,A出X,此时桌上的序列为:

K,2,8,7,X

当轮到B出牌时,他的牌K与桌上的纸牌序列中的K相同,则把包括K在内的以及两个K之间的纸牌都赢回来,放入自己牌的队尾。注意:为了操作方便,放入牌的顺序是与桌上的顺序相反的。
此时,A、B双方的手里牌为:
A方:[K, A, 2, A, 9, 5, A]
B方:[5, J, 5, Q, 6, K, 4, K, X, 7, 8, 2, K]

赢牌的一方继续出牌。也就是B接着出5,A出K,B出J,A出A,B出5,又赢牌了。
5,K,J,A,5
此时双方手里牌:
A方:[2, A, 9, 5, A]
B方:[Q, 6, K, 4, K, X, 7, 8, 2, K, 5, A, J, K, 5]

注意:更多的时候赢牌的一方并不能把桌上的牌都赢走,而是拿走相同牌点及其中间的部分。但无论如何,都是赢牌的一方继续出牌,有的时候刚一出牌又赢了,也是允许的。

当某一方出掉手里最后一张牌,但无法从桌面上赢取牌时,游戏立即结束。

对于本例的初始手牌情况下,最后A会输掉,而B最后的手里牌为:

9K2A62KAX58K57KJ5

本题的任务就是已知双方初始牌序,计算游戏结束时,赢的一方手里的牌序。当游戏无法结束时,输出-1。

输入为2行,2个串,分别表示A、B双方初始手里的牌序列。
输出为1行,1个串,表示A先出牌,最后赢的一方手里的牌序。

例如,
输入:
96J5A898QA
6278A7Q973

则程序应该输出:
2J9A7QA6Q6889977

再比如,
输入:
25663K6X7448
J88A5KJXX45A

则程序应该输出:
6KAJ458KXAX885XJ645

我们约定,输入的串的长度不超过30

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

import java.util.Scanner;

public class Main13 {

	static StringBuilder A;
	static StringBuilder B;
	static StringBuilder C;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String a = sc.next();
		String b = sc.next();
		A = new StringBuilder(a);
		B = new StringBuilder(b);
		C = new StringBuilder();

		boolean flagA = true;// A出牌标志
		boolean flagB = false;// B出牌标志
		while (true) {
			// A出牌
			if (flagA) {
				flagA = op(A, C);
				if (A.length() == 0) {
					System.out.println(B);
					break;
				}
				flagB = !flagA;
			}

			// B出牌
			if (flagB) {
				flagB = op(B, C);
				if (B.length() == 0) {
					System.out.println(A);
					break;
				}
				flagA = !flagB;
			}
		}
	}

	public static boolean op(StringBuilder x, StringBuilder t) {
		if (x.length() == 0)
			return false;
		boolean ans = true;
		char front = x.charAt(0);// 取第一个字符
		int i = t.indexOf(front + "");
		if (i != -1) {// 桌上有相同的牌
			/*
			 * 将这张牌插入桌上牌x的尾部,并将桌上 0~i之间的牌依次插入x的尾部
			 */
			x.append(front);
			for (int j = 0; j <= i; j++) {
				x.append(t.charAt(j));
			}
			// 从桌面上移除这些牌
			t.delete(0, i + 1);
		} else {
			// 将牌放在上面,下标为0
			t.insert(0, front);
			ans = false;
		}
		x.deleteCharAt(0);// 删除第一个字符
		return ans;
	}
}

问题描述
  X星球的流行宠物是青蛙,一般有两种颜色:白色和黑色。
  X星球的居民喜欢把它们放在一排茶杯里,这样可以观察它们跳来跳去。
  如下图,有一排杯子,左边的一个是空着的,右边的杯子,每个里边有一只青蛙。

*WWWBBB

其中,W字母表示白色青蛙,B表示黑色青蛙,*表示空杯子。

X星的青蛙很有些癖好,它们只做3个动作之一:
  1. 跳到相邻的空杯子里。
  2. 隔着1只其它的青蛙(随便什么颜色)跳到空杯子里。
  3. 隔着2只其它的青蛙(随便什么颜色)跳到空杯子里。

对于上图的局面,只要1步,就可跳成下图局面:

WWW*BBB

本题的任务就是已知初始局面,询问至少需要几步,才能跳成另一个目标局面。

输入为2行,2个串,表示初始局面和目标局面。
  输出要求为一个整数,表示至少需要多少步的青蛙跳。
样例输入
WWBB
WWBB

样例输出
2
样例输入
WWWBBB
BBB
WWW
样例输出
10
数据规模和约定
  我们约定,输入的串的长度不超过15

资源约定:
  峰值内存消耗(含虚拟机) < 256M
  CPU消耗 < 1000ms
思路:bfs

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;

public class Main14 {

	// 封装状态和层次
	private static class StateAndLevel {
		StringBuilder state;
		int level;
		int pos;

		public StateAndLevel(StringBuilder state, int level, int pos) {
			this.state = state;
			this.level = level;
			this.pos = pos;
		}

	}

	private static StringBuilder start;
	private static StringBuilder target;
	static Set<String> allState = new HashSet<>();

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		start = new StringBuilder(sc.next());
		target = new StringBuilder(sc.next());
		bfs();
	}

	public static void bfs() {
		// 将初始状态加入队列
		Queue<StateAndLevel> q = new LinkedList<StateAndLevel>();
		q.add(new StateAndLevel(start, 0, start.indexOf("*")));
		allState.add(start.toString());

		/*
		 * 不停弹出队列,一步演化 成相邻状态,判重后加入队列
		 */
		while (!q.isEmpty()) {
			StateAndLevel front = q.poll();
			StringBuilder state = front.state;
			int level = front.level;
			// 和目标值做比对,这里注意要转成String
			if (state.toString().equals(target.toString())) {
				System.out.println(level);
				break;
			}
			int pos = front.pos;
			// 演化出若干个状态
			for (int i = -3; i <= 3; i++) {
				if (i == 0)
					continue;
				if (pos + i >= 0 && pos + i < state.length()) {
					StringBuilder new_state = new StringBuilder(state);
					// 交换得到新状态
					swap(new_state, pos, pos + i);
					// 判重
					if (!allState.contains(new_state.toString())) {
						q.add(new StateAndLevel(new_state, level + 1, pos + i));
						allState.add(new_state.toString());
					}
				}
			}
		}
	}

	public static void swap(StringBuilder new_state, int i, int j) {
		char t = new_state.charAt(i);
		new_state.setCharAt(i, new_state.charAt(j));
		new_state.setCharAt(j, t);

	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值