1.【结果填空】 迷宫
X星球的一处迷宫游乐场建在某个小山坡上。
它是由10x10相互连通的小房间组成的。
房间的地板上写着一个很大的字母。
我们假设玩家是面朝上坡的方向站立,则:
L表示走到左边的房间,
R表示走到右边的房间,
U表示走到上坡方向的房间,
D表示走到下坡方向的房间。
X星球的居民有点懒,不愿意费力思考。
他们更喜欢玩运气类的游戏。这个游戏也是如此!
开始的时候,直升机把100名玩家放入一个个小房间内。
玩家一定要按照地上的字母移动。
迷宫地图如下:
UDDLUULRUL
UURLLLRRRU
RRUURLDLRD
RUDDDDUUUU
URUDLLRRUU
DURLRLDLRL
ULLURLLRDU
RDLULLRDDD
UUDDUDUDLL
ULRDLUURRR
请你计算一下,最后,有多少玩家会走出迷宫?
而不是在里边兜圈子。
请提交该整数,表示走出迷宫的玩家数目,不要填写任何多余的内容。
如果你还没明白游戏规则,可以参看一个简化的4x4迷宫的解说图:
分析:简单dfs模拟,设置好出口,遍历所有点(每次遍历需将vis数组重新设为false)就能求出最终结果。
结果:31
代码:
import java.util.Scanner;
public class Tp201701 {
static char[][] a = new char[13][13];
static boolean[][] vis;
static int[] dirx = {-1, 1, 0, 0}; //四个方向对应上下左右
static int[] diry = {0, 0, -1, 1};
static boolean flag = false;
static int cnt = 0;
static int m,n;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
m=n=10;
for(int i = 0; i<13; i++){
a[0][i] = '0'; //设置出口标志
a[m+1][i] = '0';
}
for(int i = 1; i<=m; i++){
String tem2 = in.nextLine();//复制样例输入
String tem = '0'+tem2 +'0';
a[i] = tem.toCharArray();
}
for(int i = 1; i<=m; i++){
for(int j = 1; j<=n; j++){
vis = new boolean[m+3][n+3];
flag = false;
dfs(i, j);
}
}
System.out.println(cnt);
}
private static void dfs(int x, int y) {
if(flag) return ;
if(a[x][y] == '0'){
cnt++;
flag = true;
return;
}
vis[x][y] = true;
char ch = a[x][y];
int dir = -1;
if(ch == 'D') dir = 1;
else if(ch == 'U') dir = 0;
else if(ch == 'L') dir = 2;
else if(ch == 'R') dir = 3;
int dx = x+dirx[dir];
int dy = y+diry[dir];
if(!vis[dx][dy]) dfs(dx, dy);
}
}
2.【结果填空】9数算式
观察如下的算式:
9213 x 85674 = 789314562
左边的乘数和被乘数正好用到了1~9的所有数字,每个1次。
而乘积恰好也是用到了1~9的所有数字,并且每个1次。
请你借助计算机的强大计算能力,找出满足如上要求的9数算式一共有多少个?
注意:
- 总数目包含题目给出的那个示例。
- 乘数和被乘数交换后作为同一方案来看待。
分析:爆破,不过怎么暴力求解是决定时间复杂度的关键,一开始我用左边的数i从1到100000,左边第二个操作数j则是(j,1000000),时间复杂度太大。。后来想起来在紫书上看过的暴力的设计方法,我们可以从结果开始枚举,因为结果的范围是确定的,[1e8,1e9),每次枚举结果就快了不少。Ps:蓝桥很喜欢类似9数这种题a
结果:1625
代码:
public class Tp201702 {
static int[] num;
static int cnt = 0;
static void toNum(int x){
while(x != 0){
num[x%10]++;
x /= 10;
}
}
private static boolean check() {
for(int i = 1; i<=9; i++){
if(num[i] != 1) return false;
}
if(num[0] != 0) return false;
return true;
}
public static void main(String[] args) {
int st = (int)1e8;
int ed = (int)1e9;
for(int res = st; res<ed; res++){
num = new int[11];
toNum(res);
if(!check()) continue;
for(int i = 1; i<(int)(1e5); i++){
if(res % i != 0) continue;
int j = res/i;
if(j <= i) break;
num = new int[11];
toNum(i);
toNum(j);
if(check()) {
System.out.println(i+" "+j+" = "+res);
cnt++;
}
}
}
System.out.println(cnt);
}
}
5、【代码填空】 字母组串
由 A,B,C 这3个字母就可以组成许多串。
比如:“A”,“AB”,“ABC”,“ABA”,“AACBB” …
现在,小明正在思考一个问题:
如果每个字母的个数有限定,能组成多少个已知长度的串呢?
他请好朋友来帮忙,很快得到了代码,
解决方案超级简单,然而最重要的部分却语焉不详。
请仔细分析源码,填写划线部分缺少的内容。
对于下面的测试数据,小明口算的结果应该是:
6
19
注意:只填写划线部分缺少的代码,不要提交任何多余内容或说明性文字。
public class A
{
// a个A,b个B,c个C 字母,能组成多少个不同的长度为n的串。
static int f(int a, int b, int c, int n)
{
if(a<0 || b<0 || c<0) return 0;
if(n==0) return 1;
return ________________________________; //填空
}
public static void main(String[] args)
{
System.out.println(f(1,1,1,2));
System.out.println(f(1,2,3,3));
}
}
分析:简单递归,返回分别取三种情况的结果和
代码:
f(a-1, b, c, n-1)+f(a, b-1, c, n-1)+f(a, b, c-1, n-1)
6、【代码填空】 最大公共子串
最大公共子串长度问题就是:
求两个串的所有子串中能够匹配上的最大长度是多少。
比如:“abcdkkk” 和 “baabcdadabc”,
可以找到的最长的公共子串是"abcd",所以最大公共子串长度为4。
下面的程序是采用矩阵法进行求解的,这对串的规模不大的情况还是比较有效的解法。
请分析该解法的思路,并补全划线部分缺失的代码。
public class Main
{
static int f(String s1, String s2)
{
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
int[][] a = new int[c1.length+1][c2.length+1];
int max = 0;
for(int i=1; i<a.length; i++){
for(int j=1; j<a[i].length; j++){
if(c1[i-1]==c2[j-1]) {
a[i][j] = __________________; //填空
if(a[i][j] > max) max = a[i][j];
}
}
}
return max;
}
public static void main(String[] args){
int n = f("abcdkkk", "baabcdadabc");
System.out.println(n);
}
}
注意:只提交缺少的代码,不要提交已有的代码和符号。也不要提交说明性文字。
分析:简单dp入门题,直接上代码
代码:
a[i-1][j-1]+1;
7、【编程大题】 正则问题
考虑一种简单的正则表达式:
只由 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,否则按无效代码处理。
分析:一开始想简单了想用栈模拟再用贪心策略,没考虑到以下情况:
(xxx|xx|x)的情况,也就是**|的数量在一对括号中不止出现一次,以及其他情况,后来被提醒用dfs,没遇到一次(**就进入一次递归,于是代码就变得比较简单了。
代码:
import java.util.Scanner;
public class Tp201707 {
static int i,len;
static char[] arr;
static int dfs(){
int sum = 0, left = 0;
while(i < len){
if(arr[i] == '('){
i++;
sum += dfs();
continue;
}
else if(arr[i] == ')'){
i++;
break;
}
else if(arr[i] == 'x')
sum++;
else {
left = Math.max(sum, left);
sum = 0;
}
i++;
}
return Math.max(left, sum);
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
arr = in.nextLine().toCharArray();
len = arr.length;
System.out.println(dfs());
}
}
8、【编程大题】 包子凑数
小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有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
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。
提交程序时,注意选择所期望的语言类型和编译器类型。
分析:欧几里得+dfs,由判断所有笼数的最大公约数是不是1得到结果是否为INF,证明略。。后暴搜一波。(在官网的练习系统上测了一下,最后一个测试点超时。。To be continued…
代码:
import java.util.Arrays;
import java.util.Scanner;
public class Tp201708 {
static int cnt,ed,n;
static boolean flag = false;
static int[] arr;
static void dfs(int cur){
if(flag) return ;
if(cur == ed){
flag = true;
return;
}
if(cur > ed) return;
for(int i = 0; i<n; i++){
dfs(cur+arr[i]);
}
}
static int gcd(int a, int b){
if(b == 0) return a;
return gcd(b, a%b);
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
arr = new int[n];
for(int i = 0; i<n; i++){
arr[i] = in.nextInt();
}
int gcdnum = arr[0];
for(int i = 1; i<n; i++){
gcdnum = gcd(gcdnum, arr[i]);
}
//如果笼数的最大公约数不是1就是INF
if(gcdnum != 1){
System.out.println("INF");
return;
}
Arrays.sort(arr);
int num = 0; //记录最大连续能取到的数
for(int i = 1; i<=100*100; i++){
ed = i;
flag = false;
dfs(0);
if(flag) num++;
else {
num = 0;
cnt++;
}
if(num >= arr[0]){ //最大连续能取到的数大于最小笼数 以后的就都能取到了
System.out.println(cnt);
break;
}
}
}
}
9、【编程大题】 分巧克力
儿童节那天有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,否则按无效代码处理。
分析:本来以为是几何题,后来仔细看题发现只是简单运算,所以,不要方,问题不大。一开始想着爆破,但是一定是会超时的,后来从大神那了解到用二分,自己当初为啥没想到TAT。。(已在官网练习系统上AC,重写输入输出流才过TAT
代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class Main {
static int maxn = (int)1e9+10;
static int n,k;
static int[] x,y;
static int check(int tem){
int cnt = 0; //记录切边长为tem的蛋糕一共能切出多少块
for(int i = 0; i<n; i++){
cnt += (x[i]/tem)*(y[i]/tem);
}
return cnt;
}
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
in.nextToken();
n = (int)in.nval;
in.nextToken();
k = (int)in.nval;
x = new int[n];
y = new int[n];
for(int i = 0; i<n; i++){
in.nextToken();
x[i] = (int)in.nval;
in.nextToken();
y[i] = (int)in.nval;
}
int left = -1, right = maxn;
int res = 0; //res记录满足条件的最大边长
//二分
while(right-left > 1){
int mid = (left+right)/2;
if(check(mid) >= k) {
res = Math.max(res, mid);
left = mid;
}
else right = mid;
}
out.println(res);
out.flush();
}
}