目 录
- 三、猜字母
- 六、奇怪的分式
- 七、扑克排序
- 八、分糖果
- 九、地宫取宝
三、猜字母
把abcd…s共19个字母组成的序列重复拼接106次,得到长度为2014的串。
接下来删除第1个字母(即开头的字母a),以及第3个,第5个等所有奇数位置的字母。
得到的新串再进行删除奇数位置字母的动作。如此下去,最后只剩下一个字母,请写出该字母。【解析】:模拟
构建StringBuilder并初始化
注意每删除一个数下标会发生变化
找到规律后写出循环
StringBuilder sb=new StringBuilder();
for(int i=1;i<=106;i++)
for(int j=97;j<116;j++)
sb.append((char)j);
while(true) {
if(sb.length()==1){
System.out.println(sb.charAt(sb.length()-1));
break;
}
for(int i=0;i<sb.length();i++) {
sb.deleteCharAt(i);
}
}
六、奇怪的分式
上小学的时候,小明经常自己发明新算法。一次,老师出的题目是: 1/4 乘以 8/5 小明居然把分子拼接在一起,分母拼接在一起,答案是:18/45老师刚想批评他,转念一想,这个答案凑巧也对啊,真是见鬼!
对于分子、分母都是 1~9 中的一位数的情况,还有哪些算式可以这样计算呢?
请写出所有不同算式的个数(包括题中举例的)。
显然,交换分子分母后,例如:4/1 乘以 5/8 是满足要求的,这算做不同的算式。
但对于分子分母相同的情况,2/2 乘以 3/3 这样的类型太多了,不在计数之列!
【解析】:枚举、最大公约数
判断两个分式是否相等,只需判断约分后的值是否相等
暴力枚举所有情况,判断约分后是否相等
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int ans=0;
//暴力枚举所有情况
for(int a=1;a<10;a++) {
for(int b=1;b<10;b++) {
if(a!=b)
for(int c=1;c<10;c++) {
for(int d=1;d<10;d++) {
//判断约分后是否相等
if(c!=d&&Arrays.equals(f(a*c,b*d), f(a*10+c,b*10+d)))
ans++;
}}}}
System.out.println(ans);
}
//约分
static int[] f(int a, int b) {
int[] x = new int[2];
for(int i=a;i>1;i--) {
if(b%i==0&&a%i==0) {
x[0]=a/i;
x[1]=b/i;
return x;
}
}
x[0]=a;
x[1]=b;
return x;
}
七、扑克排序
A A 2 2 3 3 4 4, 一共4对扑克牌。请你把它们排成一行。
要求:两个A中间有1张牌,两个2之间有2张牌,两个3之间有3张牌,两个4之间有4张牌。
请填写出所有符合要求的排列中,字典序最小的那个。
例如:22AA3344 比 A2A23344 字典序小。当然,它们都不是满足要求的答案。【解析】:全排列
全排列扑克牌,再判断
- 两个A中间有1张牌 -> 两个A下标差为2
- 如何区分重复 -> s.lastIndexOf(‘A’) - s.indexOf(‘A’)
- 如何去重复 -> 利用set集合不能有重复的特性
static char[] arr= {'A','A','2','2','3','3','4','4'};
static Set<String> set=new HashSet<>(); //去重
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
f(0);
}
//全排列
static void f(int k) {
if(k==arr.length&&check()) {
set.add(Arrays.toString(arr));
}
for(int i=k;i<arr.length;i++) {
char t=arr[k];
arr[k]=arr[i];
arr[i]=t;
f(k+1);
t=arr[k];
arr[k]=arr[i];
arr[i]=t;
}
}
//检查是否满足条件
static boolean check() {
String s=new String(arr);
if(s.lastIndexOf('A') - s.indexOf('A') == 2 && s.lastIndexOf('2') - s.indexOf('2') == 3
&& s.lastIndexOf('3') - s.indexOf('3') == 4 && s.lastIndexOf('4') - s.indexOf('4') == 5)
return true;
return false;
}
八、分糖果
有n个小朋友围坐成一圈。老师给每个小朋友随机发偶数个糖果,然后进行下面的游戏:
每个小朋友都把自己的糖果分一半给左手边的孩子。
一轮分糖后,拥有奇数颗糖的孩子由老师补给1个糖果,从而变成偶数。
反复进行这个游戏,直到所有小朋友的糖果数都相同为止。
你的任务是预测在已知的初始糖果情形下,老师一共需要补发多少个糖果。
【格式要求】
程序首先读入一个整数N(2<N<100),表示小朋友的人数。
接着是一行用空格分开的N个偶数(每个偶数不大于1000,不小于2)
要求程序输出一个整数,表示老师需要补发的糖果数。3
2 2 44
【解析】:模拟、枚举
数组的操作,
每轮按要求更改小朋友的糖果数
糖果数为奇数,则补一个,答案++
当所有小朋友糖果数相等则停止循环
注意:所有小朋友是同时分糖果
所以需要一个变量暂存第一个的初始值
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int[] arr = new int[n];
for (int i = 0; i < arr.length; i++)
arr[i] = scan.nextInt();
int ans = 0;
while (true) {
int t = arr[0];
for (int i = 0; i < n - 1; i++) {
arr[i] = arr[i] / 2 + arr[i + 1] / 2;
if ((arr[i] & 1) == 1) {
ans++;
arr[i]++;
}
}
arr[n - 1] = arr[n - 1] / 2 + t / 2;
if ((arr[n-1] & 1) == 1) {
ans++;
arr[n-1]++;
}
if (check(arr, n)) {
System.out.print(ans);
return;
}
}
}
static boolean check(int[] a, int n) {
int t = a[0];
for (int i = 1; i < n; i++)
if (a[i] != t)
return false;
return true;
}
九、地宫取宝
X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。
地宫的入口在左上角,出口在右下角。
小明被带到地宫的入口,国王要求他只能向右或向下行走。
走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。
当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。
请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。
【数据格式】
输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)
接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值
要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。2 3 2
1 2 3
2 1 514
*【60分解析】:递归
第一步:递归参数(选择物品后什么会发生变化)
位置移动 -> x、y 坐标
宝贝价值比 小明手中任意宝贝价值 都大 -> 最大值 max
当前手中有几件宝贝 -> cnt
第二步:限制条件
下标越界 -> 回溯
走到终点 -> 判断是否满足要求(正好取k个宝贝)
注意终点格子的宝贝也要判断是否可取( cnt==k-1 && cur>max )
第三步:主体
每个节点有四种走法
拿物品向右或向下,
不拿物品向右或向下
static int[][] map=new int[50][50];
static int n,m,k;
static long ans;
static final long MOD=1000000007;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
n=scan.nextInt();
m=scan.nextInt();
k=scan.nextInt();
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
map[i][j]=scan.nextInt();
}
}
dfs(0,0,-1,0);//第一个点价值可能为0
System.out.println(ans);
}
static void dfs(int x, int y, int max, int cnt) {
if(x==n||y==m)
return;
int cur=map[x][y];
if(x==n-1&&y==m-1) {
if(cnt==k||(cnt==k-1&&cur>max)) {//最后一个格子可能取
ans++;
if(ans>MOD) ans%=MOD;
}
}
if(cur>max) { //可以取这个物品
dfs(x+1,y,cur,cnt+1);
dfs(x,y+1,cur,cnt+1);
}
//对于价值小,或者价值大但不取这个物品
dfs(x+1,y,max,cnt);
dfs(x,y+1,max,cnt);
}
【满分解析】:记忆化搜索、动态规划
使用记忆数组用 递归参数 作为下标储存 递归结果,
其余部分参考上面
static int n,m,k;
static int[][] val=new int[51][51];
static long[][][][] dp=new long[51][51][15][15];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
m=sc.nextInt();
k=sc.nextInt();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
val[i][j]=sc.nextInt();
}
}
for(int i=0;i<51;i++)
for(int j=0;j<51;j++)
for(int k=0;k<15;k++)
for(int l=0;l<15;l++)
dp[i][j][k][l]=-1; //初始化为-1
System.out.println(dfs(0,0,-1,0));
}
static long dfs(int x,int y,int max,int cnt){
if(dp[x][y][max+1][cnt]!=-1) //传入的是-1下标越界,所以实际存取的时候+1
return dp[x][y][max+1][cnt];
if(x==n||y==m||cnt>k)
return 0;
int cur=val[x][y];
if(x==n-1&&y==m-1){
if(cnt==k||(cnt==k-1&&cur>max))
return 1;
return 0;
}
long ans=0; //要保存在记忆数组的值
if(cur>max){
ans+=dfs(x+1,y,cur,cnt+1);
ans+=dfs(x,y+1,cur,cnt+1);
}
ans+=dfs(x+1,y,max,cnt);
ans+=dfs(x,y+1,max,cnt);
return dp[x][y][max+1][cnt]=ans%1000000007;
}