算法学习笔记(Java)
这是博主自己学习算法的心路历程,会参考很多其他优秀的作品,如果任何做的不正确的地方,还请大家多多指正!
今天学习的是合法的括号
下面展示的是 代码
。
import java.util.Scanner;
public class 合法的括号 {
static int n = 0;
static int sum = 0;
static void dfs(int left, int right) {
if (left <= n) {
dfs(left + 1, right);
}
if (left > right) {
dfs(left, right + 1);
}
if (right > n) {
sum++;
// return;
}
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
n = input.nextInt();
dfs(1, 1);
System.out.println(sum);
}
}
要点:左括号的数量一定大于等于右括号 (是拿出来的括号,不是剩余括号)
- 输入的n相当于有多少对括号
- 第一步,当左括号少于n的时候,添加左括号
- 第二步,当右括号少于左括号的时候,添加右括号
- 第三步,当右括号小于等于n的时候才sum++
蓝桥杯练习系统(圆的面积)
- 重点内容 java输出的数保留n位小数
下面就是保留七位小数,以此类推
System.out.println(String.format("%.7f", c));
蓝桥杯练习系统(查找整数)
import java.util.Scanner;
public class 蓝桥杯练习系统 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int a[]=new int [n];
for (int i = 0; i < a.length; i++) {
a[i]=input.nextInt();
}
int num=input.nextInt();
for (int i = 0; i < a.length; i++) {
if (num==a[i]) {
System.out.println(i+1);
return;
}
}
System.out.println(-1);
}
}
记住这里是return了,意思就是直接结束代码的遍历
如果最后还是没有匹配的数的话就返回-1
蓝桥杯练习系统(字母图形)
import java.util.Scanner;
public class 蓝桥杯练习系统 {
public static void main(String[] args) {
char s1='A';
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int m=input.nextInt();
int a[][]=new int [n][m];
for (int i = 0; i < a.length; i++) {
s1=(char)('A'+i);
char s2='A';
for (int j = 0; j < a[i].length; j++) {
if (s1>'A') {
System.out.print(s1--);
}else {
System.out.print(s2++);
}
}
System.out.println();
}
}
}
- 这里记得是字母是char类型
- s1=(char)(‘A’+i); 这里是把i的类型也转换为char类型
- 从第二行开始就分成两部分 1是大于A的部分就做–,2是小于A的部分就做++
- 记住s2要在循环里面定义,因为每一次都要更新重置
蓝桥杯练习系统(杨辉三角)
import java.util.Scanner;
public class 蓝桥杯练习系统 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int a[][] = new int[n][n];
for (int i = 0; i < a.length; i++) {
for (int j = 0; j <= i; j++) {
if (i == j || j == 0) {
a[i][j] = 1;
} else {
a[i][j] = a[i - 1][j - 1] + a[i - 1][j];
}
System.out.print(a[i][j] + " ");
}
System.out.println();
}
}
}
- 记住这是一个二维数组
- 仔细观察这里的循环,第二次循环 j<=i 因为每多一行就会多一个数字 第0行一个 第一行2个 第2行3个 所以这里是大于等于
- 找对相对应的关系 当j= =0 || j= =i 时a[i][j]==1,其余的情况就是a[i][j] = a[i - 1][j - 1] + a[i - 1][j];
- 记住题目给的格式,比如在每一个字符后加上空格!!!
蓝桥杯练习系统(01字串)
- 方法一:暴力输出
- 方法二:5个循环
- 方法三:二进制转换输出以及字符类型的转换
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
System.out.println("00000");
System.out.println("00001");
System.out.println("00010");
System.out.println("00011");
System.out.println("00100");
System.out.println("00101");
System.out.println("00110");
System.out.println("00111");
System.out.println("01000");
System.out.println("01001");
System.out.println("01010");
System.out.println("01011");
System.out.println("01100");
System.out.println("01101");
System.out.println("01110");
System.out.println("01111");
System.out.println("10000");
System.out.println("10001");
System.out.println("10010");
System.out.println("10011");
System.out.println("10100");
System.out.println("10101");
System.out.println("10110");
System.out.println("10111");
System.out.println("11000");
System.out.println("11001");
System.out.println("11010");
System.out.println("11011");
System.out.println("11100");
System.out.println("11101");
System.out.println("11110");
System.out.println("11111");
}
}
public class Main{
public static void main(String[] args){
for(int i=0;i<32;i++){
System.out.print(i%32/16);
System.out.print(i%16/8);
System.out.print(i%8/4);
System.out.print(i%4/2);
System.out.println(i%2);
}
}
}
import java.util.Scanner;
public class 蓝桥杯练习系统 {
public static void main(String[] args) {
for (int i = 0; i < 32; i++) {
String a=Integer.toBinaryString(i);
int n=Integer.parseInt(a);
System.out.printf("%05d\n",n);
}
}
}
11.2(蓝桥杯练习系统:数列特征)
import java.util.Scanner;
public class 蓝桥杯练习系统 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n= input.nextInt();
int a[]=new int[n];
for (int i = 0; i < a.length; i++) {
a[i]=input.nextInt();
}
int max=Integer.MIN_VALUE;
int min=Integer.MAX_VALUE;
int sum=0;
for (int i = 0; i < a.length; i++) {
if (a[i]>max) {
max=a[i];
}
}
for (int i = 0; i < a.length; i++) {
if (a[i]<min) {
min=a[i];
}
}
for (int i = 0; i < a.length; i++) {
sum=sum+a[i];
}
System.out.println(max);
System.out.println(min);
System.out.println(sum);
}
}
1.记住这个里int max=Integer.MIN_VALUE; int min=Integer.MAX_VALUE;,这样子能比较 (想看进一步操作的话debug一下就好了)
11月11日 (特殊的回文数)
问题描述
123321是一个非常特殊的数,它从左边读和从右边读是一样的。
输入一个正整数n, 编程求所有这样的五位和六位十进制数,满足各位数字之和等于n 。
输入格式
输入一行,包含一个正整数n。
输出格式
按从小到大的顺序输出满足条件的整数,每个整数占一行。
样例输入
52
样例输出
899998
989989
998899
很明显又是一个回文数的问题 (老生常谈了 直接上代码)
import java.util.Scanner;
public class 蓝桥杯练习系统 {
public static void F(int n) {
int a, b, c, d, e, f;
for (int i = 10000; i <= 99999; i++) {
a = i / 10000;
b = i % 10000 / 1000;
c = i % 10000 % 1000 / 100;
d = i % 10000 % 1000 % 100 / 10;
e = i % 10000 % 1000 % 100 % 10;
if (a == e && b == d && a + b + c + d + e == n) {
System.out.println(i);
}
}
for (int i = 100000; i <= 999999; i++) {
a = i / 100000;
b = i % 100000 / 10000;
c = i % 100000 % 10000 / 1000;
d = i % 100000 % 10000 % 1000 / 100;
e = i % 100000 % 10000 % 1000 % 100 / 10;
f = i % 100000 % 10000 % 1000 % 100 % 10;
if (a == f && b == e && c == d && a + b + c + d + e + f == n) {
System.out.println(i);
}
}
}
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
F(n);
}
}
直接暴力解决 不和你多bb
下面整理一个模板 (凡是遇到回文数的都可以参考下面) 比如一下是4位数内的回文数
import java.util.Scanner;
public class 蓝桥杯练习系统 {
public static void main(String[] args) {
for (int i = 1000; i <= 9999; i++) {
int a,b,c,d;
a=i/1000;
b=i%1000/100;
c=i%1000%100/10;
d=i%1000%100%10;
if (a==d&&b==c) {
System.out.println(i);
}
}
}
}
反正就是除,求余除,求余求余除,求余求余求余除(稍微看看就会懂了)
又又又又有补充了
如果该回文数是偶数位就更加好办了 下面直接上代码 下面这里是六位数的样例
import java.util.Scanner;
public class 蓝桥杯练习系统 {
public static void main(String[] args) {
for (int i = 1; i < 10; i++) {
for (int j = 1; j < 10; j++) {
for (int k = 1; k < 10; k++) {
System.out.print(i);
System.out.print(j);
System.out.print(k);
System.out.print(k);
System.out.print(j);
System.out.print(i);
System.out.println();
}
}
}
}
}
11月12号(闰年判断)
首先我们要了解什么是闰年
- 可以被4整除,但是不能被100整除的年份
- 可以被400整除的年份
在了解之后简直就是白给嘛 (下面直接附上代码)
import java.util.Scanner;
public class 蓝桥杯练习系统 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
if (n%4==0&&n%100!=0||n%400==0) {
System.out.println("yes");
}else {
System.out.println("no");
}
}
}
记住这里要记住,格式一定要按照题目的要求来做,比如叫你输出yes你就要输出yes 别给我整个Yes自作聪明 (总之就是仔细看题目)
进制转换(10转2/8/16)
不和你多bb 直接上代码
import java.util.Scanner;
public class 蓝桥杯练习系统 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
System.out.println(Integer.toBinaryString(n));//二进制输出
System.out.println(Integer.toOctalString(n));//八进制输出
System.out.println(Integer.toHexString(n));//十六进制输出
}
}
有的同学就会思考了那我各种进制的转换呢 这么多咋搞啊
import java.util.Scanner;
public class 蓝桥杯练习系统 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter a binary number: ");
String n = input.nextLine();
System.out.println("Output: " + Integer.parseInt(n, 8));
}
}
以上的代码就是8进制转10进制
parseInt(String s,int radix)就是求“int radix”进制数“String s”的十进制数是多少。
parseInt(String s,int radix) 理解为parseInt(你输入的数,这个数是什么进制的) ,返回的是十进制
这里就是8进制转换为2进制
- 先把8进制转换为10进制
- 再把10进制转换为2进制
- 70(8)-56(10)-111000(2)
在举一个例子 16进制转2进制 把 F(16)-15(10)-1111(2)
11月15日
今天学习的是水仙花数
问题描述
153是一个非常特殊的数,它等于它的每位数字的立方和,即153=1的立方+5的立方+3的立方。编程求所有满足这种条件的三位十进制数。
输出格式
按从小到大的顺序输出满足条件的三位十进制数,每个数占一行。
(废话不多说,直接上代码)
import java.util.Scanner;
public class 蓝桥杯练习系统 {
public static void main(String[] args) {
for (int i = 100; i < 999; i++) {
int bai=i/100;
int shi=i%100/10;
int ge=i%100%10%10;
if (bai*bai*bai+shi*shi*shi+ge*ge*ge==i) {
System.out.println(i);
}
}
}
}
又是一道先拿出每一个数位的数然后在开始做判断语句 记住这个公式,这里就不多说了 老生常谈
11月16日(冒泡排序)
先上代码
import java.util.Scanner;
public class 蓝桥杯练习系统 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int tmp = 0;
int n = input.nextInt();
int a[] = new int[n];
for (int i = 0; i < a.length; i++) {
a[i]=input.nextInt();
}
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - i - 1; j++) {
if (a[j ] > a[j+ 1]) {
tmp = a[j];
a[j] = a[j + 1];
a[j + 1] = tmp;
}
}
}
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
}
- 冒泡排序只需要循环n-1次,n表示有n个数
- 每一次只需要走n-i次,比如5个数,第一趟走4次,第二趟走三次,第三次走两趟… (记住这里是数组,从0开始遍历,所以这里要a[i].length-i-1)
- 记住给数组的每一个值赋值是a[i].input,这样才能够赋值进去 Debug一下就懂
11月18日(Fibonacci数列)
import java.util.Scanner;
public class Fibonacci {
public static int digui(int i) {
if (i == 1 || i == 2) {
return 1;
} else {
return digui(i - 1) + digui(i - 2);
}
}
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
System.out.println(digui(n)%10007);
// System.out.println("肥波纳妾的前15项为:");
// for (int i = 1; i < 16; i++) {
// System.out.print(digui(i) + "\t");
// if (i % 5 == 0) {
// System.out.println();
// }
// }
}
}
- 首先这一个递归在一些很少的数是可以实现的 但是如果你输入的数一大的话就是超时,蓝桥杯里的超时就是0分 所以 我们要解决这个问题
- 经过一天的摸索好像还是没有找到解决的方法
11月19日(动态规划:青蛙跳阶)
题目:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 10 级的台阶总共有多少种跳法。
- 穷举分析
当台阶数为1的时候,只有一种跳法 F(1)=1;
当台阶数为2的时候,有两种跳法,第一种是直接跳两级,第二种是先跳一级再跳一级
当台阶数为3的时候,要么先跳两级(这里就有两种方法)在跳一级 ,要么跳一级在跳两级这里就是F(3)=F(2)+F(1)
当台阶数为4的时候,先跳到第三级再调一级(F(3)),或者是先跳两级再一次跨两级F(2),所以F(4)=F(3)+F(2)
......
- 确定边界
所以我们可以得到F(1)和F(2)就是跳阶的边界
- 找出规律,确定最优子结构
找出规律,当n>=3的时候,f(n)=f(n-1)+f(n-2)
- 写出状态转移方程
n=1时F(1)=1,n=2时F(2)=2,n>=3时F(n)=F(n-1)+F(n-2)
废话不多说,直接上代码
import java.util.Scanner;
public class 青蛙跳阶 {
public static int sb(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
int a=1;
int b=2;
int c=0;
for (int i = 3; i <=n; i++) {
c=a+b;//记住过往,减少重复运算
a=b;//记住过往,减少重复运算
b=c;//记住过往,减少重复运算
}
return c;
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner input=new Scanner(System.in);
int n=input.nextInt();
System.out.println(sb(n));
}
}
是不是很简单呢,动态规划的核心思想就是拆分子问题,记住过往,减少重复运算
(2 最长递增子序列)
转载于这篇文章.
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
- 穷举
- 确定边界
- 确定最优解
- 转化方程
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
当nums只有一个元素10时,最长递增子序列是[10],长度是1.
当nums需要加入一个元素9时,最长递增子序列是[10]或者[9],长度是1。
当nums再加入一个元素2时,最长递增子序列是[10]或者[9]或者[2],长度是1。
当nums再加入一个元素5时,最长递增子序列是[2,5],长度是2。
当nums再加入一个元素3时,最长递增子序列是[2,5]或者[2,3],长度是2。
当nums再加入一个元素7时,,最长递增子序列是[2,5,7]或者[2,3,7],长度是3。
当nums再加入一个元素101时,最长递增子序列是[2,5,7,101]或者[2,3,7,101],长度是4。
当nums再加入一个元素18时,最长递增子序列是[2,5,7,101]或者[2,3,7,101]或者[2,5,7,18]或者[2,3,7,18],长度是4。
当nums再加入一个元素7时,最长递增子序列是[2,5,7,101]或者[2,3,7,101]或者[2,5,7,18]或者[2,3,7,18],长度是4.
可以发现一个规律,最长递增字序要么就是以num[i]结尾,要么就是num[i-1]结尾
nums[3]=5,以5结尾的最长子序列就是[2,5],因为从数组下标0到3遍历,只找到了子序列[2]比5小,所以就是[2]+[5]啦,即dp[4]=2
nums[4]=3,以3结尾的最长子序列就是[2,3],因为从数组下标0到4遍历,只找到了子序列[2]比3小,所以就是[2]+[3]啦,即dp[4]=2
nums[5]=7,以7结尾的最长子序列就是[2,5,7]和[2,3,7],因为从数组下标0到5遍 历,找到2,5和3都比7小,所以就有[2,7],[5,7],[3,7],[2,5,7]和[2,3,7]这些子序列,最长子序列就是[2,5,7]和[2,3,7],
它俩不就是以5结尾和3结尾的最长递增子序列+[7]来的嘛!所以,dp[5]=3 =dp[3]+1=dp[4]+1。
所以穷举得dp(i) =max(dp(j))+1,存在j属于区间[0,i-1],并且num[i]>num[j]。
max(dp(j))+1就是最优子结构
这里先直接上代码
public class 最长递增子序列 {
public static int sb(int num[]) {
if (num.length==0) {
return 0;
}
int dp[]=new int [num.length];
//dp[0]=1;
int max=1;
for (int i = 0; i < num.length; i++) {
dp[i]=1;//这里每一个数就相当与一个序列 ,1个数最长序列就是1
for (int j = 0; j < i; j++) {//这里如果j<=i就在上面那个1的基础上再加1
if (num[j]<num[i]) {
dp[i]=Math.max(dp[i], dp[j]+1);
}
}
max=Math.max(max, dp[i]);
}
return max;
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
int a[]= new int[] {10,9,2,5,3,7,101,18};
System.out.println(sb(a));
}
}
11月22日(递归算法)
转载于: 这里.
首先要了解递归算法究竟是什么,很简单,总结为四个字(自己调用自己)
其中递归有两个极其重要的思想
- 找到递推公式
- 确定递归的边界 (感觉和动态规划有点类似)
比如我要写一个1-100的累加函数,相信很大一部分同学都是这样子写的
public class 递归 {
public static int sb(int n) {
int sum=0;
for (int i = 1; i <= n; i++) {
sum=sum+i;
}
return sum;
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
System.out.println(sb(3));
}
}
那如果是要用递归算法的话是怎么操作呢?
1. 找到递归公式
sum[n]=sum[n-1]+n;
.
.
.
sum[100]=sum[99]+100;
sum[99]=sum[98]+99;
sum[98]=sum[97]+98;
sum[97]=sum[96]+97; (开心,找到递归公式了)
2.确定递归边界
sum[1]=1
啊接下来就好办了
上代码
public class 递归 {
public static int sb(int n) {
if (n==1) {
return 1;
}else {
return sb(n-1)+n;
}
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
System.out.println(sb(3));
}
}
类似的还有像斐波那契算法
(2 蓝桥杯练习:过河马)
转载于: 这里.
问题描述
在那个过河卒逃过了马的控制以超级超级多的走法走到了终点之后,这匹马表示它不开心了……
于是,终于有一天,它也过河了!
由于过河马积累了许多的怨念,所以这次它过了河之后,再也没有什么东西可以限制它,它可以自由自在的在棋盘上驰骋。一开始,它是在一个n行m列棋盘的左下角(1,1)的位置,它想要走到终点右上角(n,m)的位置。而众所周知,马是要走日子格的。可是这匹马在积累了这么多怨念之后,它再也不想走回头路——也就是说,它只会朝向上的方向跳,不会朝向下的方向跳。
那么,这匹马它也想知道,它想从起点跳到终点,一共有多少种走法呢?
输入格式
第一行两个数n,m,表示一个n行m列的棋盘,马最初是在左下角(1,1)的位置,终点在右上角(n,m)的位置。
输出格式
输出有一行,一个数表示走法数。由于答案可能很大,所以输出答案除以1000000007所得的余数即可。
通常这一种跳格子感觉就像是递归算法
- 找到递归公式
- 确定递归边界
定义一个二维数组来表示我们这个棋盘dp[100][100] (题目说的范围)
当跳了一个格子(一定是往上跳的,所以就不能回头 行数一定是加的,而且列数一定不能超过你定义的列数)
确定边界:经过推算 dp[2][3]和dp[3][2]是只能有一种方法跳到这里
而且每跳一次就是一个’‘日’'字,这个时候我们就会思考,中间的格子(不是边界会有几种跳法呢)
经过推算,一个点只能从这四个点跳过来,上一下代码
import java.util.Scanner;
public class 过河马 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
int dp[][] = new int[100][100];
Scanner input = new Scanner(System.in);
int h = input.nextInt();//h是行数
int l = input.nextInt();//l是列数
dp[2][3] = dp[3][2] = 1;
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= l; j++) {
if (i == 1) {
dp[i][j] = 0;//当行数为1的时候,dp为0,因为怎么也跳不到这个地方
}
if (i - 2 > 1 && j + 1 <= l) {//i做减法的时候一定要大于1,因为一开始就是1回不去的! j做加法也不能超过边界
dp[i][j] += dp[i - 2][j + 1];
dp[i][j] %= 1000000007;
}
if (i - 1 > 1 && j + 2 <= l) {//i做减法的时候一定要大于1,因为一开始就是1回不去的! j做加法也不能超过边界
dp[i][j] += dp[i - 1][j + 2];
dp[i][j] %= 1000000007;
}
if (i - 1 > 1 && j - 2 >= 1) {//i做减法的时候一定要大于1,因为一开始就是1回不去的! j做减法也要大于等于1 因为j是行数可以等于1
dp[i][j] += dp[i - 1][j - 2];
dp[i][j] %= 1000000007;
}
if (i - 2 > 1 && j - 1 >= 1) {//i做减法的时候一定要大于1,因为一开始就是1回不去的! j做减法也要大于等于1 因为j是行数可以等于1
dp[i][j] += dp[i - 2][j - 1];
dp[i][j] %= 1000000007;
}
}
}
System.out.println(dp[h][l]);
}
}
11月24日(深度优先搜索dfs 数字的全排列)
这里的理念都来自与<啊哈算法>这本书噢,感兴趣的朋友可以入手看一看
今天学习的是深度优先算法,也是个人认为一个很重要的算法
实现的功能是数字的全排列,深度优先算法有一个很容易理解的形容词(不撞南墙不回头,就是一直往深处干,干不动了再返回)
这里我们为了更加具体,我们就假设是3的全排列吧,我们设置3个盒子,每个盒子只能放入1个数字,这里我们做一个约定,每次到一个盒子面前时,都先放1号,然后放入2号,最后放入3号
当我们走到第一个盒子的时候,按照约定,只能放入1这个数字
走到第二个盒子的时候,只能放入2这个数字,走到第三个盒子的时候,只能放入3这个数字
然后我们再往后走一步到第四个盒子,发现没有第四个盒子啊,这个时候就能确定一种排列了 (这就结束了吗,当然没有,我们要实现的是全排列)
按照之前的约定,我们走会第三个盒子,需要取回放在第三个盒子的牌(就是3),当我们想往3号盒子重新放入数字时发现只有3这个数字可以取,
所以我们要走回去第二个盒子取回第二个数字,这时候手上就有2,3两张牌了,之前2号盒子已经放好了2,按照约定2号盒子放入3,然后走到下一个盒子,
现在手上只有2这个数字了,所以就直接往里面放3号,然后走到第四个盒子,没有第四个盒子,这样又是一个排序了,一直重复这一个过程就可以实现全排列了
废话不多说,直接上代码
import java.util.Scanner;
public class txt {
static int book[];
static int a[];
static int n;
public static void dfs(int step) {
if (step == n + 1) {//当走到n+1个盒子的时候,就返回,到南墙了要回头了
for (int i = 1; i <= n; i++) {//到南墙的时候,也就是到n+1的时候就遍历输出一次
System.out.print(a[i]);
}
System.out.println();//这里才是换行的时候123这样才换一次行嘛
}
for (int i = 1; i <= n; i++) {
if (book[i] == 0) {//如果此时手上有i这个数字book数组只是来确定这个数字还在不在手上 0表示在手上
a[step] = i;//如果数字i的话,就把它放进当前的盒子
book[i] = 1;//放进盒子后,数字就不在手上了,所以就为1
dfs(step + 1);//接着再走去下一个盒子
book[i] = 0;//这就是往回走,记得要收回刚刚尝试的数字,这样才能进行下一次的尝试
}
}
return;
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
n = input.nextInt();
a = new int[10];
book = new int[10];
dfs(1);
}
}
注意事项
- 要一开始从上面静态定义好这个数,比如n,这样才能在方法内和主函数引用
- 要理解book数组的含义
- 最后要拿回数字,debug一下应该就能懂了
下面这个是深度优先搜索 的基本模型
void dfs(int step){
判断边界
尝试每一种可能for(i=1;i<=n;i++){
继续下一步 dfs(step+1);
}
返回
}
11月25日(坑爹的奥数)
□□□ X □□□ = □□□ 将数字1 ~ 9填入□中使等式成立,每个数字只能使用一次 例:173 + 286 = 459 和286 + 173 = 459是同一种组合
这里用到的也是深度优先搜索(DFS)
具体也是类似上面的做法,下面先直接上一下代码了
import java.util.Scanner;
public class 一到九的盒子加法啊哈算法 {
static int book[];
static int a[];
//static int n;
static int sum=0;
public static void sb(int step) {
if (step==10) {
if (a[1]*100+a[2]*10+a[3]+a[4]*100+a[5]*10+a[6]==a[7]*100+a[8]*10+a[9]) {
sum++;
System.out.printf("%d%d%d+%d%d%d=%d%d%d\n", a[1], a[2], a[3],//记住这里这个格式,通用格式
a[4], a[5], a[6], a[7], a[8], a[9]);
}
}
for (int i = 1; i <=9; i++) {
if (book[i]==0) {
a[step]=i;
book[i]=1;
sb(step+1);
book[i]=0;
}
}
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner input=new Scanner(System.in);
a=new int [10];
book=new int [10];
sb(1);
System.out.println(sum/2);
}
}
- 记得最后要除2
- 当往回走到时候记得要book[i]==0
11月28日(拿金币)
来自: 思想来源.
问题描述
有一个N x N的方格,每一个格子都有一些金币,只要站在格子里就能拿到里面的金币。你站在最左上角的格子里,每次可以从一个格子走到它右边或下边的格子里。请问如何走才能拿到最多的金币。
输入格式
第一行输入一个正整数n。
以下n行描述该方格。金币数保证是不超过1000的正整数。
首先先想一下这个程序想要考察你什么东西
- 首先就是要建立一个NxN的二维数组嘛,往数组内传值
- 接着要遍历数组内的数据,看看怎么加起来才是最多嘛
- 思考一下,我们只能往右下或者下边走,那么第一列的数是不是只能从左边走进右边a[i][j]=a[i][j]+a[i-1][j];,第一列的数上方走下来a[i][j]=a[i][j]+a[i][j-1](发现居然有边界)
- 那如果不是两个边界的数呢,噢这个数在中间,它可以由右边的数或者上面的数走过来,那怎么判断两个数谁大的,用那个Math.max啊!中间的数就是a[i][j]=a[i][j]+Math.max(a[i][j-1], a[i-1][j]);,然后在一直走下去走到尽头吗,每一个格子都有值,加上途中的值,肯定是到最后一个点才是最大值,所以每走一次都要用上一次加进来的最大值来继续看看走右边还是下面才能是最大值.
- 找到边界,找到递推公式,没跑了,递归!
直接上代码
import java.util.Scanner;
import java.util.function.ToDoubleBiFunction;
public class 拿金币 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int a[][] = new int[n][n];
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
a[i][j]=input.nextInt();
}
}
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
if (i==0&&j>0) {//上边界 j从0开始遍历大于0就不是第一列
a[i][j]=a[i][j]+a[i][j-1];//只能从左边来
}
else if (j==0&&i>0) {//左边界 i从0开始遍历 i>0就不是第一行
a[i][j]=a[i][j]+a[i-1][j];//只能从上面来
}
else if (i>0&&j>0) {//中间的数
a[i][j]=a[i][j]+Math.max(a[i][j-1], a[i-1][j]);
}
}
}
System.out.println(a[n-1][n-1]);//因为是从0开始遍历
}
}
12月5日(凑算式)
凑算式
B DEF
A + --- + ------- = 10
C GHI
(如果显示有问题,可以参见【图1.jpg】)
这个算式中A~I代表0~9的数字,不同的字母代表不同的数字。
比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。
这个算式一共有多少种解法?
有没有发现很像我们之前写过的一个题目(坑爹的奥数) 没错就是深度优先搜索(dfs)
public class 凑算式 {
static double sum;
static double a[];
static double book[];
public static void sb(int step) {
if (step==10) {
if (a[1]+a[2]/a[3]+(a[4]*100+a[5]*10+a[6])/(a[7]*100+a[8]*10+a[9])==10) {
sum++;
}
}
for (int i = 1; i <=9; i++) {
if (book[i]==0) {
a[step]=i;
book[i]=1;
sb(step+1);
book[i]=0;
}
}
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
a=new double [10];
book=new double [10];
sb(1);
System.out.println((int)sum);
}
}
注意事项
- 一定要是double类型,不然就会精度消失,sum就会很大很大
- 应该题目要求最后输出的是int 所以System.out.println((int)sum);
2020.1.13 终于放假了回来更新
【问题描述】
吃鸡类(即大逃杀类型)游戏,往往为了让玩家交战,会设计安全区(跑毒圈)的机制。
小明设计了一款新的吃鸡游戏,也拥有这个机制,下一个跑毒圈会刷在上一个跑毒圈内。为
了验证小明写的算法的正确性,请你编写一个程序判断小明两次刷圈是否内含或内切(无视
圈的先后顺序,只要之间相互内含或内切即可)。
【输入格式】
第一行包含一个正整数t,表示输入多少组数据。
第2到t + 1行,每行包含六个正整数 𝑥𝑎, 𝑦𝑎, 𝑟𝑎, 𝑥𝑏, 𝑦𝑏, 𝑟𝑏,分别表示圆 a 和圆 b 的 x 轴坐
标、y 轴坐标和半径。
【输出格式】
包含 t 行,分别为每组数据中两圆是否内含或内切的结果。内含或内切则输出“true”,
否则输出“false”。
【样例输入】
3
0 1 1 0 0 2
5 5 5 2 2 2
10 4 20 5 6 7
【样例输出】
true
false
true
【评测用例规模与约定】
−1 × 10的六次方 ≤ 𝑥𝑎, 𝑦𝑎, 𝑟𝑎, 𝑥𝑏, 𝑦𝑏, 𝑟𝑏 ≤ 1 × 10的六次方
由题可知,只要判断两个圆是否内切或者内含,如果是的话就返回true,不是的话就返回false
如何判断两个圆是否内切或者内含呢
- 确定两圆的圆心位置坐标距离
- 确定两圆半径的距离
其中两点间的距离公式就是
两个半径之间的距离就是r1-r2的绝对值
若两点间距离小于或等于两个半径之间的距离就说明两个圆内含或者内切!!
(直接上代码)
import java.util.Scanner;
public class 跑毒圈 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int s=0;
String a[]=new String [n];
while (n!=0) {
double x1 = input.nextDouble();
double y1 = input.nextDouble();
double r1 = input.nextDouble();
double x2 = input.nextDouble();
double y2 = input.nextDouble();
double r2 = input.nextDouble();
double l = Math.abs(r1 - r2);//半径距离差
double z1 = Math.pow((x1 - x2), 2);//两点间距离公式
double z2 = Math.pow((y1 - y2), 2);//两点间距离公式
if (Math.sqrt(z1+z2)<=l) {//两点间距离公式
a[s]="true";
}else {
a[s]="false";
}
n--;
s++;
}
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
}
还有一个要注意的细节就是题目要求是连续输入几个数,所以我们就先创建一个string数组,然后每一次输入就把值存进数组,等遍历完变量最后再输出数组内的值!
2022年1月16号
【题目描述】
给出一个字符串,从第一个字符开始,数到 1999 个字符,删除该字符,再从下一个字符
继续,数到字符串结尾后则调到开头,一直到只剩下一个字符,如果是‘?’则输出“yes”否
则输出“no”。
【输入格式】
一个长度为 L 的字符串。
【输出格式】
"yes"或者"no"
【输入样例】
1sd!@#QSD123qsdliuoiej1ghmdv;oipasr203i451qGfasfq2?3k1k3pospzixc1m23l1hlb
【输出样例】
yes
【评测用例规模与约定】
1 ≤ 𝐿 ≤ 3 × 10的4次方
一看这一些题目,反复循环,很容易就联想到使用队列,因为每一次循环把队头元素移除然后在放回给队尾这样就可以实现反复循环
上代码
import java.util.ArrayList;
import java.util.Scanner;
public class 最后一个字符 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String n = input.nextLine();
StringBuffer a=new StringBuffer(n);//转为stringbuffer这样内存就不会爆了
ArrayList<Character> al = new ArrayList<Character>();//创建队列
int count = 0;
for (int i = 0; i < a.length(); i++) {
al.add(a.charAt(i));//a中的每一位分别放进数组
}
while (true) {
char tmp = al.remove(0);//队列是从0开始
if (count == 1998) {//队列一开始是从0开始,所以这里是数到1998
count = 0;
} else {
al.add(tmp);
count++;//记住这里才是count++,如果放在外面的话当count变成0的时候,下一次循环开始又变成1了
}
if (al.size() == 1) {//当队列的长度为1时
char x=al.remove(0);//再移出一位,此时x才是队列的最后一位
if (x == '?') {
System.out.println("yes");
break;
} else {
System.out.println("no");
break;
}
}
}
}
}
- 注意这里要使用的是stringbuffer,因为如果使用string的话内存可以会爆掉,string是有字符串长度的
- 注意count++的位置,一定是放在else条件里面(debug了很久的…)
- 注意当队列里面只剩最后一个字符时,要创建多一个变量把这个数据拿出来,此时这是才是题目所说的最后一个字符
1月19日(母牛的故事)递归
题目 1004: [递归]母牛的故事
时间限制: 1Sec 内存限制: 128MB 提交: 92969 解决: 28952
题目描述
有一头母牛,它每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。请编程实现在第n年的时候,共有多少头母牛?
输入
输入数据由多个测试实例组成,每个测试实例占一行,包括一个整数n(0<n<55),n的含义如题目中描述。
n=0表示输入数据的结束,不做处理。
输出
对于每个测试实例,输出在第n年的时候母牛的数量。
每个输出占一行。
样例输入
2
4
5
0
样例输出
2
4
6
这不就是相当于斐波那契的变式吗,简直一样一样的
import java.util.ArrayList;
import java.util.Scanner;
public class 母牛的故事 {
public static int miu(int n) {//穷举 列出对应方程
if (n<=4) {
return n;
}else {
return miu(n-1)+miu(n-3);
}
}
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
ArrayList<Integer> al=new ArrayList<Integer>();//创建一个队列来存储数据
while (!input.hasNext("0")) {//当输入为0的时候结束该循环
int n=input.nextInt();
int x=miu(n);
al.add(x);//把此时的值存进队列中
}
while (al.size()!=0) {
int tmp=al.remove(0);//依次输出队列中的每一个元素,然后打印出来
System.out.println(tmp);
}
}
}
1月20日(FJ的字符串) 递归
资源限制
时间限制:1.0s 内存限制:512.0MB
问题描述
FJ在沙盘上写了这样一些字符串:
A1 = “A”
A2 = “ABA”
A3 = “ABACABA”
A4 = “ABACABADABACABA”
… …
你能找出其中的规律并写所有的数列AN吗?
输入格式
仅有一个数:N ≤ 26。
输出格式
请输出相应的字符串AN,以一个换行符结束。输出中不得含有多余的空格或换行、回车符。
样例输入
3
样例输出
ABACABA
这里很容易看得出是递归的
- 当n=1时,return A
- 当n>1时,return f(n-1) char(‘A’+n-1)f(n-1)
import java.util.Scanner;
public class Main {
public static String sb(int n) {
if (n==1) {
return "A";
}else {
return sb(n-1)+(char)('A'+n-1)+sb(n-1);//这里要n-1是因为这里从1开始,因为A就是1,其中sb(n-1)就是为前一项的值
}
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
System.out.println(sb(n));
}
}
2022.2.10(嘻嘻回来更新了 过年好)
从今天开始我们要开始着重刷搜索(广搜,深搜)的题目了,让我们开始吧
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
有N根木棍,需要将其粘贴成M个长木棍,使得最长的和最短的的差距最小。
输入格式
第一行两个整数N,M。
一行N个整数,表示木棍的长度。
输出格式
一行一个整数,表示最小的差距
样例输入
3 2
10 20 40
样例输出
10
数据规模和约定
N, M<=7
- 这一题就是用的搜索实现的 (记住dfs的步骤)
import java.util.Scanner;
public class 粘木棍 {
static int MinSum = 0;
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner input = new Scanner(System.in);
int N = input.nextInt();// 开始有N根木棍
int M = input.nextInt();// 粘成M根木棍
int a[] = new int[N];
for (int i = 0; i < a.length; i++) {
a[i] = input.nextInt();
MinSum = MinSum + a[i];
}
int c[] = new int[N];// c数组是确定元素是否被使用
int b[] = new int[M];// 这个数组是存储粘后的木棍数
dfs(a, b, c, 0, N, M);//从0开始遍历,因为是遍历数组
System.out.println(MinSum);
}
public static void dfs(int a[], int b[], int c[], int k, int n, int m) {// k用来遍历数组 dfs步骤
if (k < n) {
for (int i = 0; i < m; i++) {// 遍历每一次的相加
if (c[k] == 0) {
b[i] = b[i] + a[k];
c[k] = 1;
dfs(a, b, c, k + 1, n, m);
c[k] = 0;
b[i] = b[i] - a[k];
}
}
} else {
int max = b[0];//因为要从b[0]开始遍历,所以要等于b[0]!!
int min = b[0];
for (int i = 0; i < m; i++) {
if (b[i] > max) {
max = b[i];//遍历数组更新最大值
}
if (b[i] < min) {
min = b[i];//遍历数组更新最小值
}
}
if (max - min < MinSum) {
MinSum = max - min;//更新最小差值
}
}
}
}
2022年2月11日
今天仍然练习的是搜索
车的放置
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
在一个n*n的棋盘中,每个格子中至多放置一个车,且要保证任何两个车都不能相互攻击,有多少中放法(车与车之间是没有差别的)
输入格式
包含一个正整数n
输出格式
一个整数,表示放置车的方法数
样例输入
2
样例输出
7
数据规模和约定
n<=8
【样例解释】一个车都不放为1种,放置一个车有4种,放置2个车有2种。
import java.util.Scanner;
public class 车的放置 {
static int count = 1;// 什么都不放就是一种
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();// 行数
int a[] = new int[n];// 列数
dfs(a, 0);// 从第0行开始 因为是数组
System.out.println(count);
}
public static void dfs(int a[], int n) {
if (n > a.length - 1) {// 数组从0开始计算
return;
}
for (int i = 0; i < a.length; i++) {// dfs步骤 很经典
if (a[i] == 0) {// 0表示没有放车
a[i] = 1;// 1表示放了车
count++;
dfs(a, n + 1);
a[i] = 0;
}
}
dfs(a, n + 1);
}
}
2022年2月21日
试题 算法训练 数字游戏
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
给定一个1~N的排列a[i],每次将相邻两个数相加,得到新序列,再对新序列重复这样的操作,显然每次得到的序列都比上一次的序列长度少1,最终只剩一个数字。
例如:
3 1 2 4
4 3 6
7 9
16
现在如果知道N和最后得到的数字sum,请求出最初序列a[i],为1~N的一个排列。若有多种答案,则输出字典序最小的那一个。数据保证有解。
输入格式
第1行为两个正整数n,sum
输出格式
一个1~N的一个排列
样例输入
4 16
样例输出
3 1 2 4
数据规模和约定
0<n<=10
import java.util.Scanner;
public class 数字游戏 {
static int n;//有多少个数字
static int sum;//相加的结果
static boolean bool = true;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
n = input.nextInt();
sum = input.nextInt();
int array[] = new int[n];
int visit[] = new int[n + 1];//访问标记 因为下面是遍历到等于1
dfs(0, array, visit);
}
public static void dfs(int step, int arr[], int vis[]) {//搜索函数
if (bool == true) {
for (int i = 1; i <= n; i++) {//搜索的步骤 很重要
if (vis[i] == 0) {
arr[step] = i;
vis[i] = 1;
dfs(step + 1, arr, vis);
vis[i] = 0;
}
}
}
if (step == n) {//找到n个数字
int arr1[] = new int[n];//建立一个新数组用来相加
for (int i = 0; i < n; i++) {
arr1[i] = arr[i];
}
for (int i = 1; i < n; i++) {//这个就是类似数字金字塔的相加 这个很秀 建议记住他
for (int j = 0; j < n - i; j++) {
arr1[j] = arr1[j] + arr1[j + 1];
}
}
if (arr1[0] == sum) {//最后两者相等时候输出
for (int i : arr) {//遍历arr数组内的所有元素然后输出
System.out.print(i + " ");
}
bool = false;
return;
} else {
return;
}
}
}
}
其中我发现一个很有意思的东西,就是前面那个加法 这个遍历的方法很好用
public class 数字金字塔加法来自数字游戏 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
int sum = 0;
int a[] = new int[] { 1, 2, 3, 4 };
for (int i = 1; i < 4; i++) {
for (int j = 0; j < 4 - i; j++) {
a[j] = a[j] + a[j + 1];
sum = a[j];
}
}
System.out.println(sum);
}
}
上面这个就是假设n=4的,元素为1,2,3,4的数组,就是每次遍历数组内的相隔元素都相加,最后得出一个答案
2022年2月23日
试题 算法训练 跳马
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
一个8×8的棋盘上有一个马初始位置为(a,b),他想跳到(c,d),问是否可以?如果可以,最少要跳几步?
输入格式
一行四个数字a,b,c,d。
输出格式
如果跳不到,输出-1;否则输出最少跳到的步数。
样例输入
1 1 2 3
样例输出
1
数据规模和约定
0<a,b,c,d≤8且都是整数。
- 因为马走日,所以马在棋盘里最多有8中跳跃方法
- 同时要考虑边界问题(这里我们用dfs方法来实现)
import java.util.Scanner;
public class 跳马 {
static int a,b,c,d;
static int min_step=-1;
static int sb[][]=new int [9][9];
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner input=new Scanner(System.in);
a=input.nextInt();
b=input.nextInt();
c=input.nextInt();
d=input.nextInt();
dfs(a, b, 0);
if (min_step==-1) {//这里说明无论怎么走也走不到终点,下面就没有赋值,就一直是-1
System.out.println(-1);
}else {
System.out.println(min_step);
}
}
public static void dfs(int i,int j,int step) {
if (min_step!=-1&&step>min_step) {//如果步数已经大于已知最小的步数,直接返回
return;
}
if (i==c&&j==d) {//到达终点的时候才赋值给min_step
min_step=step;
return;
}
if (i>=1&&i<=8&&j>=1&&j<=8&&sb[i][j]==0) {
sb[i][j]=1;
dfs(i - 2, j - 1, step + 1);
dfs(i - 2, j + 1, step + 1);
dfs(i - 1, j - 2, step + 1);
dfs(i - 1, j + 2, step + 1);
dfs(i + 1, j - 2, step + 1);
dfs(i + 1, j + 2, step + 1);
dfs(i + 2, j - 1, step + 1);
dfs(i + 2, j + 1, step + 1);
sb[i][j]=0;
}
}
}
2022年3月2日(蓝桥杯 算法提高 因式分解)
试题 算法提高 因式分解
资源限制
时间限制:5.0s 内存限制:256.0MB
试题
将大于1的自然数N进行因式分解,满足:
N=а1а2а3…аm且1<а1≤а2≤…≤аm<N
编一程序,输入N(1<N<10^9)
输入要求
N由键盘输入。
输出要求
① 第1行至第M行输出所有的M种方案(顺序不限)
② 第M+1行输出方案总数T。
样例输入
N=12
样例输出
12=26
12=223
12=34
T =3
import java.util.Scanner;
public class 因式分解 {
static int count = 0;
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner input = new Scanner(System.in);
StringBuffer s = new StringBuffer(input.next());// 因为这里输入的是T=12,要用stringbuffer转换
int n = Integer.valueOf(s.substring(2, s.length()));// 然后这里用substring截取到这个值
dfs(n, n + "=", 2);
System.out.println("T " +"="+ count);// 注意这里输出有一个空格 很坑
}
public static void dfs(int n, String s, int m) {
if (n == 1) { // 如果n=1的话就直接返回函数
return;
}
String s1 = s;
for (int i = m; i <= n; i++) {
if (n % i == 0) { // 找出n可以被i整除的数
int m1 = n / i;
// 下面两个判断是因为要实现 N=а1а2а3…аm 且1<а1≤а2≤…≤аm <N
if (m1 < m) {
return;
}
if (m1 < i) {
return;
}
s = s + i + "*";
System.out.println(s + m1);// 这里的"+m1"要放在这里 很细节
dfs(m1, s, i);
count++;// 计数器加一
s = s1;// 回溯回溯 这个很重要
}
}
}
此题理解来自本网博主:白白凉铁血
}
2022年3月14日(印章)
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
输入格式
一行两个正整数n和m
输出格式
一个实数P表示答案,保留4位小数。
样例输入
2 3
样例输出
0.7500
数据规模和约定
1≤n,m≤20
- 当n=1时,只有1种类型的话,m无论拿多少种都是拿完了,所以dp[m][n]=1
- 若大于一种,而且买的张数少于种数,肯定就是0
- 当买的全部卡片都是一种时,1/n的i次方*n
- dp[i][j]=dp[i-1][j]* (j * 1.0/n)+dp[i-1][j-1]*((n-j+1)*1.0/n); 有重复的说明第i张的种类在前面的i-1张前面已经出现过一样的,前面出现了j种,所以再次出现的概率就是j/n, 第二种就是第i张的种类在前面没有出现过,所以第i张要不同与前面i-1张,前面有j-1种,这一张就是n-(j-1)种减去有的就是剩下的,概率就是n-(j-1)/n
- 涉及到double的运算一定要乘1.0,不然就会精度丢失
import java.util.Scanner;
public class TText {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();// n种
int m = input.nextInt();//m张
double dp[][] = new double[m + 1][n + 1];
double p = 1.0 / n;
if (n == 1) { //当只有1种类型时
dp[m][n] = 1;
System.out.printf("%.4f", dp[m][n]);
return;
}
if (n > 1 && m < n) { //若大于一种,而且买的张数少于种数,肯定就是0
dp[m][n] = 0;
System.out.printf("%.4f", dp[m][n]);
return;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (i<j) {
dp[i][j]=0;
}
if (j==1) {
dp[i][j]=Math.pow(p, i-1); //当买的全部卡片都是一种时,1/n的i次方*n
}else {
dp[i][j]=dp[i-1][j]*(j*1.0/n)+dp[i-1][j-1]*((n-j+1)*1.0/n);
// 第一个是最后一张是和前面是有重复的(j*1.0/n),第二个是最后一张和前面没有重复的(n-j+1)*1.0/n
//一定要*1.0,不然会精度丢失
}
}
}
System.out.printf("%.4f", dp[m][n]);
}
}
2022年3月21日(合并检测+口罩分配)
1.首先就是合并检测
新冠疫情由新冠病毒引起,最近在 A 国蔓延,为了尽快控制疫情,A 国准
备给大量民众进病毒核酸检测。
然而,用于检测的试剂盒紧缺。
为了解决这一困难,科学家想了一个办法:合并检测。即将从多个人(k个)采集的标本放到同一个试剂盒中进行检测。如果结果为阴性,则说明这 k个人都是阴性,用一个试剂盒完成了 k 个人的检测。如果结果为阳性,则说明至少有一个人为阳性,需要将这 k 个人的样本全部重新独立检测(从理论上看,如果检测前 k − 1 个人都是阴性可以推断出第 k 个人是阳性,但是在实际操作中不会利用此推断,而是将 k 个人独立检测),加上最开始的合并检测,一共使用了 k + 1 个试剂盒完成了 k 个人的检测。A 国估计被测的民众的感染率大概是 1%,呈均匀分布。请问 k 取多少能最节省试剂盒?
【答案提交】
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
public class 合并检测 {
public static void main(String[] args) { // 清楚明白
// TODO 自动生成的方法存根
int min = 0;
int sum = Integer.MAX_VALUE;
for (int i = 1; i <= 100; i++) { //假设有100人,只有1%感染率
if (100 % i == 0) { //若该分组可以被整除
if (100 / i + i < sum) {
sum = 100 / i + i; // 如果有阳性就要测100/i+i次核酸
min = i; // 最小就是全部阴性就是,那就只用测i次
}
}
if (100 % i != 0) { //若该分组不可以被整除
if ((100 / i) + 1 + i < sum) {
sum = 100 / i + 1 + i;// 如果有阳性就要测100/i+i+1次核酸
min = i + 1;// 最小就是全部阴性就是,那就只用测i+1次
}
}
}
System.out.println(min);
}
}
口罩分配(这里用的是dfs,深度优先搜索)
某市市长获得了若干批口罩,每一批口罩的数目如下:(如果你把以下文字复制到文本文件中,请务必检查复制的内容是否与文档中的一致。在试题目录下有一个文件 mask.txt,内容与下面的文本相同)
9090400
8499400
5926800
8547000
4958200
4422600
5751200
4175600
6309600
5865200
6604400
4635000
10663400
8087200
4554000
现在市长要把口罩分配给市内的 2 所医院。由于物流限制,每一批口罩只能全部分配给其中一家医院。市长希望 2 所医院获得的口罩总数之差越小越好。请你计算这个差最小是多少?
【答案提交】
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
import java.util.LinkedList;
import java.util.Scanner;
public class TText {
public static int min = Integer.MAX_VALUE;
public static int a[] = { 9090400, 8499400, 5926800, 8547000,
4958200, 4422600, 5751200, 4175600, 6309600, 5865200,
6604400, 4635000, 10663400, 8087200, 4554000 };
public static boolean book[] = new boolean [a.length];
public static int sum = 0;
public static void main(String[] args) {
for (int i = 0; i < a.length; i++) {
sum=sum+a[i];
}
dfs(0);
System.out.println(min);
}
public static void dfs(int temp) { //temp来记录口罩的总值
if (temp>=sum/2)
{
min = Math.min(min, Math.abs(sum-temp*2)); //找超出一半部分的最小,这样就能找到最小的差值
return;
}
for (int x = 0; x < a.length; x++) { // dfs的样式
if (book[x]==false) {
book[x]=true;
dfs(temp+a[x]);
book[x]=false;
}
}
}
}
2022年3月23日
斐波那契最大公约数(大数考察+jdk文档的使用)
分类计数(字符转化+jdk文档的使用)
- character.isDigit(char ch) 判断是否为数字
- character.isLowerCase(char ch) 判断是否为小写字母
- character.isUpperCase(char ch) 判断是否为大写字母
题目描述
输入一个字符串,请输出这个字符串包含多少个大写字母,多少个小写字母,多少个数字。
【输入格式】
输入一行包含一个字符串。
【输出格式】
输出三行,每行一个整数,分别表示大写字母、小写字母和数字的个数。
【样例输入】
1+a=Aab
【样例输出】
1
3
1
【评测用例规模与约定】
对于所有评测用例,字符串由可见字符组成,长度不超过 100。
八次求和 (大数运算和jdk的使用,和上面一样)
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
BigInteger sum = BigInteger.ZERO;
BigInteger a=BigInteger.ONE;
for (int i = 1; i <= n; i++) {
BigInteger b=BigInteger.ONE;
BigInteger sb = a.pow(8); // 看jdk文档pow就是幂函数
sum=sum.add(sb);
a=a.add(b);
}
BigInteger x=sum.mod(new BigInteger("123456789")); //相当于字符串的使用
System.out.println(x);
// BigInteger ss = new BigInteger("42343235352");
// System.out.println(ss);
}
}
2022年3月29日
最大子字典序列,最大子字典序列一定包括字符串的最后一位
import java.awt.List;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class TText {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
StringBuffer s=new StringBuffer();
s.append(input.next()); // stringBuffer的输入,stringBuffer不会爆掉内存
StringBuffer a = new StringBuffer();
char max = 'a';
for (int i = s.length() - 1; i >= 0; i--) { // 最大子字典序列从最后一个开始找
if (s.charAt(i) >= max) {
max = s.charAt(i);
a.append(max);
}
}
a.reverse(); // 这里记得要将序列翻转
System.out.println(a);
}
}
数列求值
题目描述
给定数列 1, 1, 1, 3, 5, 9, 17, …,从第 4 项开始,每项都是前 3 项的和。求 第 20190324 项的最后 4 位数字。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个 4 位整数(提示:答案的千位不为 0),在提交答案时只填写这个整数,填写 多余的内容将无法得分。
// 这一题一读题目就知道是大数运算了 类似斐波那契数列
import java.awt.List;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
public class TText {
public static void main(String[] args) {
//System.out.println(4565445%10000);
BigInteger a = BigInteger.ONE;
BigInteger b = BigInteger.ONE;
BigInteger c = BigInteger.ONE;
BigInteger sum = BigInteger.ZERO;
for (int i = 4; i <= 20190324; i++) {
sum = a.add(b.add(c).mod(new BigInteger("10000"))); //每一个数都求余的话可以节省运算的时间(大概要九秒)
a=b.mod(new BigInteger("10000"));
b=c.mod(new BigInteger("10000"));
c=sum.mod(new BigInteger("10000"));
}
System.out.println(sum);
}
}
回文日期
2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。
因为如果将这个日期按 yyyymmdd 的格式写成一个 8 位数是 20200202,恰好是一个回文数。
我们称这样的日期是回文日期。
有人表示 20200202 是“千年一遇” 的特殊日子。
对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。
也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。
对此小明也不认同,因为大约 100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。
算不上“千年一遇”,顶多算“千年两遇”。
给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。
只需注意一个东西,月份要小于等于12大于等于1,天数要小于等于31!!
import java.util.Scanner;
public class 回文日期 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int data = input.nextInt();
int ge,shi,bai,qian,wan,shiwan,baiwan,qianwan;
int a[] = new int[500];
int k = 0 ;
for (int i = 10000101; i < 100000000; i++) {
ge = i % 10;
shi = i / 10 % 10;
bai = i / 100 % 10;
qian = i / 1000 % 10;
wan = i / 10000 % 10;
shiwan = i / 100000 % 10;
baiwan = i / 1000000 % 10;
qianwan = i / 10000000 % 10;
if (ge == qianwan && shi == baiwan && bai == shiwan &&
wan == qian && 1 <= qian * 10 + bai
&& qian * 10 + bai <= 12 && shi * 10 + ge <= 31) {
a[k]=i; // 符合的数据存进数据
k++;
}
}
for (int i = 0; i < 400; i++) {
ge = a[i] % 10;
shi = a[i] / 10 % 10;
bai = a[i] / 100 % 10;
qian = a[i] / 1000 % 10;
wan = a[i] / 10000 % 10;
shiwan = a[i] / 100000 % 10;
baiwan = a[i] / 1000000 % 10;
qianwan = a[i] / 10000000 % 10;
if (ge==qianwan&&shi==baiwan&&bai==shiwan&&qian==wan&&a[i]>data) {
System.out.println(a[i]);
break;
}
}
for (int i = 0; i < 400; i++) {
ge = a[i] % 10;
shi = a[i] / 10 % 10;
bai = a[i] / 100 % 10;
qian = a[i] / 1000 % 10;
wan = a[i] / 10000 % 10;
shiwan = a[i] / 100000 % 10;
baiwan = a[i] / 1000000 % 10;
qianwan = a[i] / 10000000 % 10;
if (ge==bai&&ge==shiwan&&ge==qianwan&&bai==shiwan&&bai==qianwan&&shiwan==qianwan
&&shi==qian&&shi==wan&&shi==baiwan&&qian==wan&&qian==baiwan&&wan==baiwan
&&a[i]>data) {
System.out.println(a[i]);
break;
}
}
}
}
数的分解
把 2019 分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包 含数字 2 和 4,一共有多少种不同的分解方法?
注意交换 3 个整数的顺序被视为同一种方法,例如 1000+1001+18 和 1001+1000+18 被视为同一种。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
public class TText {
public static void main(String[] args) {
int count = 0;
for (int i = 1; i <= 2019; i++) {
for (int j = 1; j <= 2019; j++) {
for (int k = 1; k <= 2019; k++) {
if ( i + j + k == 2019&&sb(i) == true && sb(j) == true && sb(k) == true
&& i != j && i != k && j != k
) {
count++;
}
}
}
}
System.out.println(count / 6);
}
public static boolean sb(int a) { // 判断是否有数字4和2
while (a > 0) { // 这里记得要判断a是否大于0
if (a % 10 == 4 || a % 10 == 2) {
return false;
}
a = a / 10;
}
return true;
}
}
不同字串
【问题描述】 一个字符串的非空子串是指字符串中长度至少为 1 的连续的一段字符组成 的串。
例如,字符串aaab 有非空子串a, b,aa, ab, aaa, aab, aaab,一共 7 个。 注意在计算时,只算本质不同的串的个数。
请问,字符串0100110001010001 有多少个不同的非空子串?
【答案提交】这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
import java.util.HashSet;
public class TText {
public static void main(String[] args) {
String a= "0100110001010001";
HashSet<String> b = new HashSet<String>(); // hashset可以去重
for (int i = 0; i < a.length(); i++) {
for (int j = i; j < a.length(); j++) {
b.add(a.substring(i, j+1)); // substring截取包括头结点,不包括尾结点
}
}
System.out.println(b.size());
}
}
最短路径
下图给出了一个迷宫的平面图,其中标记为1的是障碍,0的是可以通行的地方
010000
000100
001001
110000
迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这 个它的上、下、左、右四个方向之一。
对于上面的迷宫,从入口开始,找出最短的路径步数
import java.awt.List;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.function.IntToDoubleFunction;
public class TText {
static int min = 9999;
static int a[][] = new int[51][51]; // 定义数组长度
static int book[][] = new int[51][51]; // 访问数组,看该位置是否被访问
static int n,m,p, q;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int m = input.nextInt();
for (int i = 1; i <=n; i++) {
for (int j = 1; j <=m; j++) {
a[i][j]=input.nextInt();
}
}
int startx = input.nextInt(); // 起点
int starty = input.nextInt();
p = input.nextInt(); // 终点
q = input.nextInt();
dfs(startx, starty, 0);
System.out.println(min);
}
public static void dfs(int x, int y, int step) {
int next[][] = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; // 右下左上
int tx, ty;
if (x == p && y == q) { // 当到达终点的时候,更新最小值
if (step < min) {
min = step;
}
return;
}
for (int i = 0; i < 4; i++) { // 依次向右下左上遍历
tx = x+next[i][0];
ty = y+next[i][1];
if (tx<1||tx>n||ty<1||ty>n) { // 位置要在范围内才行
continue;
}
if (a[tx][ty] == 0 && book[tx][ty] == 0) { // 当当前位置为0的时候且仍未被访问的时候才可以访问
book[tx][ty] = 1; // 这里就是dfs的常规步骤了
dfs(tx, ty, step+1);
book[tx][ty] = 0;
}
}
}
}
有关int转化为string类型相关事项
public class TText {
public static void main(String[] args) {
int a= 4;
String bString = a+"";
System.out.println(bString);
}
}
最大公约数和最小公倍数
import java.awt.List;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.function.IntToDoubleFunction;
public class TText {
public static void main(String[] args) {
int a = 9, b = 3;
System.out.println(gcd(a, b));
System.out.println(lcm(a, b));
}
public static int gcd(int a, int b) { // 最大公约数
return b == 0 ? a:gcd(b,a%b);
}
public static int lcm(int a,int b) { // 最小公倍数
return a*b/gcd(a, b);
}
}
承压计算
X星球的高科技实验室中整齐地堆放着某批珍贵金属原料。
每块金属原料的外形、尺寸完全一致,但重量不同。
金属材料被严格地堆放成金字塔形。
其中的数字代表金属块的重量(计量单位较大)。
最下一层的X代表30台极高精度的电子秤。
假设每块原料的重量都十分精确地平均落在下方的两个金属块上,
最后,所有的金属块的重量都严格精确地平分落在最底层的电子秤上。
电子秤的计量单位很小,所以显示的数字很大。
工作人员发现,其中读数最小的电子秤的示数为:2086458231
请你推算出:读数最大的电子秤的示数为多少?
注意:需要提交的是一个整数,不要填写任何多余的内容。
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
public class 承压计算{
static double a[][]= new double [][]{
{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},
{0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0,0}
};
public static void main(String[] args) {
double max = 0;
double min = Double.MAX_VALUE;
for (int i = 1; i < 30; i++) {
for (int j = 0; j <= i; j++) {
if (j==0) {
a[i][j]=a[i][j]+a[i-1][j]/2.0;
}
if (j==i) {
a[i][j]=a[i][j]+a[i-1][j-1]/2.0;
}
if (j>0&&j<i) {
a[i][j]=a[i][j]+a[i-1][j]/2.0+a[i-1][j-1]/2.0;
}
}
}
for (int i = 0; i < 30; i++) {
if (a[29][i]<min) {
min = a[29][i];
}
if (a[29][i]>max) {
max = a[29][i];
}
}
System.out.println(2086458231/min*max);
}
}
世纪末的星期
曾有邪教称1999年12月31日是世界末日。当然该谣言已经不攻自破。还有人称今后的某个世纪末的12月31日,如果是星期一则会…
有趣的是,任何一个世纪末的年份的12月31日都不可能是星期一!! 于是,“谣言制造商”又修改为星期日…1999年的12月31日是星期五,请问:未来哪一个离我们最近的一个世纪末年(即xx99年)的12月31日正好是星期天(即星期日)?
请回答该年份(只写这个4位整数,不要写12月31等多余信息)
import java.util.Calendar;
public class 世纪末的星期 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Calendar c = Calendar.getInstance();
for (int i = 2099; i <100000; i=i+100) {
// c.set(Calendar.YEAR, i);
// c.set(Calendar.MONTH, 11); // 0代表的是1月份
// c.set(Calendar.DATE, 31); // 天数就是从1开始
c.set(i, 11, 31);
if (c.get(Calendar.DAY_OF_WEEK)==1) { // 1代表的是星期日
System.out.println(i);
break;
}
}
}
}
马虎的算式
小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了。有一次,老师出的题目是:36 x 495 = ? 他却给抄成了:396 x 45 = ?但结果却很戏剧性,他的答案竟然是对的!!因为 36 * 495 = 396 * 45 = 17820 类似这样的巧合情况可能还有很多,比如:27 * 594 = 297 * 54 假设 a b c d e 代表1~9不同的5个数字(注意是各不相同的数字,且不含0)能满足形如: ab * cde = adb * ce 这样的算式一共有多少种呢?请你利用计算机的优势寻找所有的可能,并回答不同算式的种类数。满足乘法交换律的算式计为不同的种类,所以答案肯定是个偶数。
答案直接通过浏览器提交。
注意:只提交一个表示最终统计种类数的数字,不要提交解答过程或其它多余的内容。
public class TText {
public static void main(String[] args) {
int count =0;
for (int a = 1; a < 10; a++) {
for (int b = 1; b < 10; b++) {
for (int c = 1; c < 10; c++) {
for (int d = 1; d < 10; d++) {
for (int e = 1; e < 10; e++) {
int x1= a*10+b;
int y1 = c*100+d*10+e;
int x2 = a*100+d*10+b;
int y2 = c*10+e;
if (x1*y1==x2*y2&&a!=b&&a!=c&&a!=d&&a!=e&&b!=c&&b!=d&&b!=e&&c!=d&&c!=e&&d!=e) {
count++;
}
}
}
}
}
}
System.out.println(count);
}
}
振兴中华
小明参加了学校的趣味运动会,其中的一个项目是:跳格子。
地上画着一些格子,每个格子里写一个字,如下所示:(也可参见p1.jpg)
从我做起振
我做起振兴
做起振兴中
起振兴中华
比赛时,先站在左上角的写着“从”字的格子里,可以横向或纵向跳到相邻的格子里,但不能跳到对角的格子或其它位置。一直要跳到“华”字结束。
要求跳过的路线刚好构成“从我做起振兴中华”这句话。
请你帮助小明算一算他一共有多少种可能的跳跃路线呢?
答案是一个整数,请通过浏览器直接提交该数字。
import java.awt.List;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Scanner;
import java.util.function.IntToDoubleFunction;
public class TText {
static char a[][]= {{'从','我','做','起','振'},
{'我','做','起','振','兴'},{'做','起','振','兴','中'},{'起','振','兴','中','华'}};
static int count =0 ;
public static void main(String[] args) {
char b[]=new char[8];
dfs(0, 0, 0, b);
System.out.println(count);
}
public static void dfs(int step, int x, int y, char b[]) {
if (x > 3) { // 行
return;
}
if (y > 4) { // 列
return;
}
if (step > 7) {
return;
}
b[step]=a[x][y]; // 记录步数内容
if (step==7) {
if (sb(b)) {
count++;
}
}
dfs(step+1, x+1, y, b);
dfs(step+1, x, y+1, b);
}
public static boolean sb(char b[]) {
if ("从我做起振兴中华".equals(String.valueOf(b))) {
return true;
}else {
return false;
}
}
}