算法笔记_125:算法集训之编程大题集一(Java)
目录
1 砝码称重
5个砝码 用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量。
如果只有5个砝码,重量分别是1,3,9,27,81。则它们可以组合称出1到121之间任意整数重量(砝码允许放在左右两个盘中)。
本题目要求编程实现:对用户给定的重量,给出砝码组合方案。
例如:
用户输入:
5
程序输出:
9-3-1
用户输入:
19
程序输出:
27-9+1 要求程序输出的组合总是大数在前小数在后。
可以假设用户的输入的数字符合范围1~121。
//方法1:三进制处理
package com.liu.ex1; import java.util.ArrayList;
import java.util.Scanner; public class Main {
public static int[] value = new int[6]; public void printResult(int n) {
int count = 0;
while(n > 0) { //把n转换为三进制数
value[count++] = n % 3;
n = n / 3;
}
//对n的三进制数进行处理,得到砝码组合结果
for(int i = 0;i < 5;i++) {
if(value[i] >= 2) {
value[i] = value[i] - 3;
value[i + 1] = value[i + 1] + 1;
}
} ArrayList<Integer> list = new ArrayList<Integer>();
for(int i = 5;i >= 0;i--) {
if(value[i] == 1) {
int a = (int) Math.pow(3, i);
list.add(a);
} else if(value[i] == -1) {
int a = (int) (-1 * Math.pow(3, i));
list.add(a);
}
} System.out.print(list.get(0));
for(int i = 1;i < list.size();i++) {
if(list.get(i) > 0) {
System.out.print("+");
}
System.out.print(list.get(i));
}
return;
} public static void main(String[] args) {
Main test = new Main();
Scanner in = new Scanner(System.in);
int n = in.nextInt();
test.printResult(n);
}
}
//方法2:DFS搜索
package com.liu.ex1; import java.util.ArrayList;
import java.util.Scanner; public class Main1 {
public static int[] value = {1,3,9,27,81};
public static int n = 0;
public static ArrayList<Integer> result = new ArrayList<Integer>(); public int getSum() {
int sum = 0;
for(int i = 0;i < result.size();i++)
sum += result.get(i);
return sum;
} public void dfs(int step) {
if(step == 5) {
if(getSum() == n) {
int i = result.size() - 1;
for(;i >= 0;i--) {
if(result.get(i) != 0) {
System.out.print(result.get(i));
i--;
break;
}
}
for(;i >= 0;i--) {
if(result.get(i) == 0)
continue;
if(result.get(i) > 0)
System.out.print("+");
System.out.print(result.get(i));
}
}
} else {
for(int i = -1;i <= 1;i++) {
int a = i * value[step];
result.add(a);
dfs(step + 1);
result.remove(result.size() - 1);
}
}
} public static void main(String[] args) {
Main1 test = new Main1();
Scanner in = new Scanner(System.in);
n = in.nextInt();
test.dfs(0);
}
}
2 公式解析
在某些应用中,为了支持灵活性,往往用到自定义的公式。 比如,有如下的原始公式集合: int add(int x, int y): 返回x与y的和 int add(int x, int y, int z): 返回x,y,z三个数的和 int min(int x, int y): 返回x,y中较小的值 int max(int x, int y): 返回x,y中较大的值 int doubleMe(int x): 返回 x 的2倍 给出一个自定义公式串 add(min(5,3),max(2,8),add(1,doubleMe(1))) 通过手工计算可以得出结果为:14 本题的任务是:编写一个解析程序,能够对由上述原始公式任意组合出来的公式计算其结果。也就是输入一个自定义公式串,输出它的计算结果(可以不考虑输入公式本身有语法错误的情况)。 输入的公式串中可以含有多余的空格,类似: add( min(5, 3) , max(2 , 8) ) 也是合法的公式。 程序输入:公式串
程序输出:该公式的计算值
package com.liu.ex2; import java.util.Scanner;
import java.util.Stack; public class Main {
public static Stack<String> operation = new Stack<String>(); //存放运算符
public static Stack<Character> bracket = new Stack<Character>(); //存放左括号
public static Stack<Integer> number = new Stack<Integer>(); //存放运算参数
public static Stack<Integer> count = new Stack<Integer>(); //存放运算符参数个数 public int add(int[] N) {
if(N.length == 3)
return N[0] + N[1] + N[2];
return N[0] + N[1];
} public int max(int[] N) {
return N[0] > N[1] ? N[0] : N[1];
} public int min(int[] N) {
return N[0] < N[1] ? N[0] : N[1];
} public int doubleMe(int[] N) {
return 2 * N[0];
} public boolean judgeChar(char s) {
if(s >= 'a' && s <= 'z' || s >= 'A' && s <= 'Z')
return true;
return false;
} public boolean judgeNumber(char s) {
if(s >= '0' && s <= '9')
return true;
return false;
} public void getResult(String A) {
String temp = "";
for(int i = 0;i < A.length();i++) {
if(judgeChar(A.charAt(i))) {
temp = temp + A.charAt(i);
i = i + 1;
while(judgeChar(A.charAt(i))) {
temp = temp + A.charAt(i);
i++;
}
i = i - 1;
operation.push(temp);
count.push(0); //刚寻找到一个运算符,并初始化一个参数个数为0
temp = "";
} else if(A.charAt(i) == '(') {
bracket.push(A.charAt(i));
} else if(judgeNumber(A.charAt(i))) {
temp = temp + A.charAt(i);
i = i + 1;
while(judgeNumber(A.charAt(i))) {
temp = temp + A.charAt(i);
i++;
}
i = i - 1;
number.push(Integer.valueOf(temp));
count.push(count.pop() + 1); //此处用于计算当前栈顶运算符实际参数个数
temp = "";
} else if(A.charAt(i) == ')') { //此时要进行运算
bracket.pop(); //栈顶左括号出栈
String tempOpera = operation.pop();
int[] N = new int[count.pop()];
if(!count.empty())
count.push(count.pop() + 1);
for(int j = 0;j < N.length;j++)
N[j] = number.pop();
int result = 0;
if(tempOpera.equals("add"))
result = add(N);
else if(tempOpera.equals("max"))
result = max(N);
else if(tempOpera.equals("min"))
result = min(N);
else if(tempOpera.equals("doubleMe"))
result = doubleMe(N);
number.push(result);
}
}
} public static void main(String[] args) {
Main test = new Main();
Scanner in = new Scanner(System.in);
String A = in.nextLine();
test.getResult(A);
System.out.println(number.pop());
}
}
3 购物券消费方案
公司发了某商店的购物券1000元,限定只能购买店中的m种商品。每种商品的价格分别为m1,m2,…,要求程序列出所有的正好能消费完该购物券的不同购物方法。 程序输入:
第一行是一个整数m,代表可购买的商品的种类数。
接下来是m个整数,每个1行,分别代表这m种商品的单价(0<m<1000)。
程序输出:
第一行是一个整数,表示共有多少种方案
第二行开始,每种方案占1行,表示对每种商品购买的数量,中间用空格分隔。
例如: 输入:
2
200
300
则应输出:
2
2 2
5 0 输入:
2
500
800
则应输出:
1
2 0 输入:
1
999
则应输出:
0 多个方案间的顺序不重要。
package com.liu.ex3; import java.util.ArrayList;
import java.util.Scanner; public class Main {
public static ArrayList<Integer> list = new ArrayList<Integer>();
public static int[][] value;
public static int m;
public static int count = 0;
public static String result = ""; public void dfs(int sum, int step) {
if(step == m) {
if(sum == 1000) {
for(int i = 0;i < list.size();i++) {
result += list.get(i)+" ";
}
result += "\n";
count++;
}
return;
} else {
for(int i = 0;i <= value[step][1];i++) {
sum += value[step][0] * i;
list.add(i);
dfs(sum, step + 1);
sum -= value[step][0] * i;
list.remove(list.size() - 1);
}
}
} public static void main(String[] args) {
Main test = new Main();
Scanner in = new Scanner(System.in);
m = in.nextInt();
value = new int[m][2];
for(int i = 0;i < m;i++) {
int a = in.nextInt();
int num = 1000 / a;
value[i][0] = a;
value[i][1] = num;
}
test.dfs(0, 0);
if(count == 0)
System.out.println("0");
else
System.out.println(count+"\n"+result);
}
}
4 机器人行走
某少年宫引进了一批机器人小车。可以接受预先输入的指令,按指令行动。小车的基本动作很简单,只有3种:左转(记为L),右转(记为R),向前走若干厘米(直接记数字)。 例如,我们可以对小车输入如下的指令: 15L10R5LRR10R20 则,小车先直行15厘米,左转,再走10厘米,再右转,... 不难看出,对于此指令串,小车又回到了出发地。 你的任务是:编写程序,由用户输入指令,程序输出每条指令执行后小车位置与指令执行前小车位置的直线距离。 【输入、输出格式要求】 用户先输入一个整数n(n<100),表示接下来将有n条指令。 接下来输入n条指令。每条指令只由L、R和数字组成(数字是0~100之间的整数) 每条指令的长度不超过256个字符。 程序则输出n行结果。 每条结果表示小车执行相应的指令前后位置的直线距离。要求四舍五入到小数后2位。 例如:用户输入:
5
L100R50R10
3LLL5RR4L12
LL
100R
5L5L5L5 则程序输出:
102.96
9.06
0.00
100.00
0.00 【注意】 请仔细调试!您的程序只有能运行出正确结果的时候才有机会得分!
package com.liu.ex4; import java.util.Scanner; public class Main {
public static int[] position = {0,1,2,3}; //表示机器人朝向,分别为上、左、下、右 public String getResult(String A) {
//机器人起始朝向默认为向上
int area = position[0];
double x = 0, y = 0;
for(int i = 0;i < A.length();i++) {
String temp = "";
if(A.charAt(i) == 'L') {
area = (area + 1) % 4;
} else if(A.charAt(i) == 'R') {
if(area == 0)
area = 3;
else
area = area - 1;
} else {
for(;i < A.length();i++) {
if(A.charAt(i) == 'L' || A.charAt(i) == 'R') {
i = i - 1;
break;
}
temp += A.charAt(i);
}
int num = Integer.valueOf(temp);
if(area == 0)
y = y + num;
else if(area == 1)
x = x - num;
else if(area == 2)
y = y - num;
else if(area == 3)
x = x + num;
}
}
double result = x * x + y * y;
result = Math.sqrt(result);
String tempResult = String.format("%.2f", result);
return tempResult;
} public void printResult(String[] A) {
String[] result = new String[A.length];
for(int i = 0;i < A.length;i++) {
result[i] = getResult(A[i]);
}
for(int i = 0;i < A.length;i++)
System.out.println(result[i]);
return;
} public static void main(String[] args) {
Main test = new Main();
Scanner in = new Scanner(System.in);
int n = in.nextInt();
in.nextLine();
String[] A = new String[n];
for(int i = 0;i < n;i++)
A[i] = in.nextLine();
test.printResult(A);
}
}
5 角谷步数
你听说过角谷猜想吗?
任意的正整数,比如 5, 我们从它开始,如下规则计算:
如果是偶数,则除以2,如果是奇数,则乘以3再加1.
如此循环,最终必会得到“1” ! 比如 5 的处理过程是:
5
16
8
4
2
1 一个正整数经过多少步才能变成1, 称为角谷步数。
对于5而言,步数也是5
对于1,步数为0 本题的要求是,从标准输入给定一个整数n(1<n<300)表示角谷步数
求满足这个角谷步数的最小的正整数 例如: 输入:
3
则输出:
8 输入:
4
则输出:
16 输入:
7
则输出:
3
package com.liu.ex5; import java.util.ArrayList;
import java.util.Scanner; public class Main {
public static ArrayList<Integer> list = new ArrayList<Integer>(); public void getResult() {
list.add(0);
for(int i = 1;i <= 300000;i++) {
int tempi = i;
int count = 0;
while(tempi > 1) {
if(tempi % 2 == 0) {
tempi = tempi / 2;
count++;
} else {
tempi = tempi * 3 + 1;
count++;
}
}
list.add(count);
}
return;
} public void printResult(int n) {
getResult();
int result = list.indexOf(n);
System.out.println(result);
return;
} public static void main(String[] args) {
Main test = new Main();
Scanner in = new Scanner(System.in);
int n = in.nextInt();
test.printResult(n);
}
}
6 矩形区域的交和并
在编写图形界面软件的时候,经常会遇到处理两个矩形的关系。 如图【1.jpg】所示,矩形的交集指的是:两个矩形重叠区的矩形,当然也可能不存在(参看【2.jpg】)。两个矩形的并集指的是:能包含这两个矩形的最小矩形,它一定是存在的。 本题目的要求就是:由用户输入两个矩形的坐标,程序输出它们的交集和并集矩形。 矩形坐标的输入格式是输入两个对角点坐标,注意,不保证是哪个对角,也不保证顺序(你可以体会一下,在桌面上拖动鼠标拉矩形,4个方向都可以的)。 输入数据格式:
x1,y1,x2,y2
x1,y1,x2,y2 数据共两行,每行表示一个矩形。每行是两个点的坐标。x坐标在左,y坐标在右。坐标系统是:屏幕左上角为(0,0),x坐标水平向右增大;y坐标垂直向下增大。 要求程序输出格式:
x1,y1,长度,高度
x1,y1,长度,高度 也是两行数据,分别表示交集和并集。如果交集不存在,则输出“不存在” 前边两项是左上角的坐标。后边是矩形的长度和高度。 例如,用户输入:
100,220,300,100
150,150,300,300 则程序输出:
150,150,150,70
100,100,200,200 例如,用户输入:
10,10,20,20
30,30,40,40 则程序输出:
不存在
10,10,30,30 注意: 请仔细调试!您的程序只有能运行出正确结果的时候才有机会得分! 在评卷时使用的输入数据与试卷中给出的实例数据可能是不同的。
package com.liu.ex6; import java.util.Scanner; public class Main {
public static int[][] point = new int[4][2];
public static int[][] result = new int[2][4]; public void getResult(String[] A) {
String[] tempA1 = A[0].split(",");
String[] tempA2 = A[1].split(",");
point[0][0] = Integer.valueOf(tempA1[0]);
point[0][1] = Integer.valueOf(tempA1[1]);
point[1][0] = Integer.valueOf(tempA1[2]);
point[1][1] = Integer.valueOf(tempA1[3]);
point[2][0] = Integer.valueOf(tempA2[0]);
point[2][1] = Integer.valueOf(tempA2[1]);
point[3][0] = Integer.valueOf(tempA2[2]);
point[3][1] = Integer.valueOf(tempA2[3]); //第一个矩形对角线坐标
int x1 = Math.min(point[0][0], point[1][0]);
int y1 = Math.min(point[0][1], point[1][1]);
int x2 = Math.max(point[0][0], point[1][0]);
int y2 = Math.max(point[0][1], point[1][1]);
//第二个矩形对角线坐标
int x3 = Math.min(point[2][0], point[3][0]);
int y3 = Math.min(point[2][1], point[3][1]);
int x4 = Math.max(point[2][0], point[3][0]);
int y4 = Math.max(point[2][1], point[3][1]);
if(x3 >= x2 || x1 >= x4 || y3 >= y2 || y1 >= y4) {
result[0][0] = -1; //表示交集不存在
} else {
int x = 0, y = 0, len = 0, high = 0;
if(x3 >=x1 && x3 < x2) {
if(x4 >= x2) {
x = x3;
len = x2 - x3;
} else {
x = x3;
len = x4 - x3;
}
} else if(x1 >= x3 && x1 < x4) {
if(x2 >= x4) {
x = x1;
len = x4 - x1;
} else {
x = x1;
len = x2 - x1;
}
} if(y3 >= y1 && y3 < y2) {
if(y4 >= y2) {
y = y3;
high = y2 - y3;
} else {
y = y3;
high = y4 - y3;
}
} else if(y1 >= y3 && y1 < y4) {
if(y2 >= y4) {
y = y1;
high = y4 - y1;
} else {
y = y1;
high = y2 - y1;
}
} result[0][0] = x;
result[0][1] = y;
result[0][2] = len;
result[0][3] = high;
} int x = Math.min(x1, x3);
int y = Math.min(y1, y3);
int len = Math.max(x2, x4) - x;
int high = Math.max(y2, y4) - y;
result[1][0] = x;
result[1][1] = y;
result[1][2] = len;
result[1][3] = high;
} public static void main(String[] args) {
Main test = new Main();
Scanner in = new Scanner(System.in);
String[] A = new String[2];
for(int i = 0;i < 2;i++) {
A[i] = in.next();
}
test.getResult(A);
for(int i = 0;i < 2;i++) {
for(int j = 0;j < 3;j++) {
if(i == 0 && result[0][0] == -1) {
System.out.println("不存在");
break;
} else {
System.out.print(result[i][j]+",");
}
}
if(result[0][0] != -1)
System.out.println(result[i][3]);
else {
if(i == 1)
System.out.println(result[i][3]);
}
}
}
}
7 矩阵变换加密法
一种Playfair密码变种加密方法如下:首先选择一个密钥单词(称为pair)(字母不重复,且都为小写字母),然后与字母表中其他字母一起填入至一个5x5的方阵中,填入方法如下:
1.首先按行填入密钥串。
2.紧接其后,按字母序按行填入不在密钥串中的字母。
3.由于方阵中只有25个位置,最后剩下的那个字母则不需变换。
如果密钥为youandme,则该方阵如下:
y o u a n
d m e b c
f g h i j
k l p q r
s t v w x
在加密一对字母时,如am,在方阵中找到以这两个字母为顶点的矩形:
o u a
m e b 这对字母的加密字母为该矩形的另一对顶点,如本例中为ob。
请设计程序,使用上述方法对输入串进行加密,并输出加密后的串。
另外有如下规定:
1、一对一对取字母,如果最后只剩下一个字母,则不变换,直接放入加密串中;
2、如果一对字母中的两个字母相同,则不变换,直接放入加密串中;
3、如果一对字母中有一个字母不在正方形中,则不变换,直接放入加密串中;
4、如果字母对出现在方阵中的同一行或同一列,如df或hi,则只需简单对调这两个字母,即变换为fd或ih;
5、如果在正方形中能够找到以字母对为顶点的矩形,假如字母对为am,则该矩形的另一对顶点字母中,与a同行的字母应在前面,在上例中应是ob;同样若待变换的字母对为ta,则变换后的字母对应为wo;
6、本程序中输入串均为小写字母,并不含标点、空格或其它字符。
解密方法与加密相同,即对加密后的字符串再加密,将得到原始串。
要求输入形式如下:
从控制台输入两行字符串,第一行为密钥单词(长度小于等于25),第二行为待加密字符串(长度小于等于50),两行字符串末尾都有一个回车换行符,并且两行字符串均为小写字母,不含其它字符。
在标准输出上输出加密后的字符串。
例如,若输入:
youandme
welcometohangzhou
则表示输入的密钥单词为youandme,形成的正方形如上所示;待加密字符串为welcometohangzhou。在正方形中可以找到以第一对字母we为顶点的矩形,对应另一对顶点字母为vb,因此加密后为vb,同理可找到与字母对lc,et,oh,ho对应的顶点字母对。而字母对om位于上述正方形中的同一列,所以直接以颠倒这两个字母来加密,即为mo,字母对an同理。字母对gz中的z不在上述正方形中,因此原样放到加密串中。最后剩一个字母u也原样输出。
因此输出的结果为:
vbrmmomvugnagzguu
package com.liu.ex7; import java.util.ArrayList;
import java.util.Scanner; public class Main {
public static char[][] value = new char[5][5];
public static boolean[] used = new boolean[26]; public int[] getPosition(char s) {
int[] position = new int[2];
for(int i = 0;i < 5;i++) {
for(int j = 0;j < 5;j++) {
if(value[i][j] == s) {
position[0] = i;
position[1] = j;
return position;
}
}
}
return position;
} public void getResult(String pair, String psw) {
for(int i = 0;i < 26;i++)
used[i] = false;
ArrayList<Character> list = new ArrayList<Character>();
for(int i = 0;i < pair.length();i++) {
list.add(pair.charAt(i));
int temp = pair.charAt(i) - 'a';
used[temp] = true;
}
while(list.size() < 25) {
for(int i = 0;i < 26;i++) {
if(used[i] == false) {
char temp = (char) ('a' + i);
list.add(temp);
used[i] = true;
}
if(list.size() == 25)
break;
}
}
char unUsed = 'a';
for(int i = 0;i < 26;i++) {
if(used[i] == false) {
unUsed = (char) (unUsed + i);
break;
}
}
int count = 0;
for(int i = 0;i < 5;i++)
for(int j = 0;j < 5;j++)
value[i][j] = list.get(count++); int len = psw.length();
ArrayList<Character> result = new ArrayList<Character>();
if(len % 2 == 1)
len = len - 1;
for(int i = 0;i < len;i = i + 2) {
char temp1 = psw.charAt(i);
char temp2 = psw.charAt(i + 1);
int[] position1 = getPosition(temp1);
int[] position2 = getPosition(temp2);
if(temp1 == temp2) {
result.add(temp1);
result.add(temp2);
} else if(temp1 == unUsed || temp2 == unUsed) {
result.add(temp1);
result.add(temp2);
} else if(position1[0] == position2[0] || position1[1] == position2[1]) {
result.add(temp2);
result.add(temp1);
} else {
temp1 = value[position1[0]][position2[1]];
temp2 = value[position2[0]][position1[1]];
result.add(temp1);
result.add(temp2);
}
}
if(psw.length() % 2 == 1)
result.add(psw.charAt(psw.length() - 1));
for(int i = 0;i < result.size();i++)
System.out.print(result.get(i));
return;
} public static void main(String[] args) {
Main test = new Main();
Scanner in = new Scanner(System.in);
String pair = in.next();
String psw = in.next();
test.getResult(pair, psw);
}
}
8 控制台表格
画表格 在图形环境中很容易做出漂亮的表格。但在控制台环境中就比较困难了。有的时候可以用一些符号大略地模拟:(word文档中可能不整齐,拷贝到记事本中看)
+-------+------+
|abc |xyz=tt|
+-------+------+
|hellomm|t2 |
+-------+------+ 本题目要求设计一个程序,把用户输入的内容用这种“准表格”的方式展现出来。具体的要求是:
用户输入的第一行是一个整数,表示接下来有多少行信息。接下来的每行由若干单元组成。单元间用逗号分开。
程序输出:用表格方式重新展现的输入内容。
例如: 用户输入:
3
cat,dog,good-luck
1,2,5
do not use,,that
则程序输出:(word文档中可能不整齐,拷贝到记事本中看)
+----------+---+---------+
|cat |dog|good-luck|
+----------+---+---------+
|1 |2 |5 |
+----------+---+---------+
|do not use| |that |
+----------+---+---------+
从中不难看出:
两个连续的逗号表示中间有一个内容为空的单元
列的数目由最大的单元数的那行决定
列的宽度由同列的最宽的单元决定
单元格中的信息左对齐 可以假设:用户输入的最大行数为30,可能的最多列数为40。
package com.liu.ex8; import java.util.Scanner; public class Main { public void printResult(String[] A) {
String[] tempA = A[0].split(",");
int maxLen = tempA.length;
for(int i = 1;i < A.length;i++) {
tempA = A[i].split(",");
if(maxLen < tempA.length)
maxLen = tempA.length;
}
String[][] valueA = new String[A.length][maxLen];
for(int i = 0;i < valueA.length;i++)
for(int j = 0;j < valueA[0].length;j++)
valueA[i][j] = ""; for(int i = 0;i < A.length;i++) {
tempA = A[i].split(",");
for(int j = 0;j < tempA.length;j++)
valueA[i][j] = tempA[j];
}
int[] maxJ = new int[maxLen];
for(int j = 0;j < maxLen;j++) {
for(int i = 0;i < A.length;i++) {
if(valueA[i][j].length() > maxJ[j])
maxJ[j] = valueA[i][j].length();
}
} StringBuilder opera = new StringBuilder("+");
for(int j = 0;j < maxJ.length;j++) {
for(int k = 0;k < maxJ[j];k++)
opera.append('-');
opera.append('+');
}
for(int i = 0;i < valueA.length;i++) {
System.out.println(opera);
System.out.print("|");
for(int j = 0;j < valueA[0].length;j++) {
int len = maxJ[j] - valueA[i][j].length();
String format = "";
if(len == 0)
format = "" + "%s";
else
format = "%" + len + "s";
System.out.print(valueA[i][j]);
System.out.printf(format, "");
System.out.print("|");
}
System.out.println();
}
System.out.println(opera);
return;
} public static void main(String[] args) {
Main test = new Main();
Scanner in = new Scanner(System.in);
int n = in.nextInt();
in.nextLine();
String[] A = new String[n];
for(int i = 0;i < n;i++)
A[i] = in.nextLine();
test.printResult(A);
}
}
9 拉丁方块填数字
“数独”是当下炙手可热的智力游戏。一般认为它的起源是“拉丁方块”,是大数学家欧拉于1783年发明的。 如图[1.jpg]所示:6x6的小格被分为6个部分(图中用不同的颜色区分),每个部分含有6个小格(以下也称为分组)。 开始的时候,某些小格中已经填写了字母(ABCDEF之一)。需要在所有剩下的小格中补填字母。 全部填好后,必须满足如下约束: 1. 所填字母只允许是A,B,C,D,E,F 中的某一个。 2. 每行的6个小格中,所填写的字母不能重复。 3. 每列的6个小格中,所填写的字母不能重复。 4. 每个分组(参见图中不同颜色表示)包含的6个小格中,所填写的字母不能重复。 为了表示上的方便,我们用下面的6阶方阵来表示图[1.jpg]对应的分组情况(组号为0~5):
000011
022013
221113
243333
244455
445555 用下面的数据表示其已有字母的填写情况:
02C
03B
05A
20D
35E
53F 很明显,第一列表示行号,第二列表示列号,第三列表示填写的字母。行号、列号都从0开始计算。 一种可行的填写方案(此题刚好答案唯一)为: E F C B D A
A C E D F B
D A B E C F
F B D C A E
B D F A E C
C E A F B D 你的任务是:编写程序,对一般的拉丁方块问题求解,如果多解,要求找到所有解。 【输入、输出格式要求】 用户首先输入6行数据,表示拉丁方块的分组情况。 接着用户输入一个整数n (n<36), 表示接下来的数据行数 接着输入n行数据,每行表示一个预先填写的字母。 程序则输出所有可能的解(各个解间的顺序不重要)。 每个解占用7行。 即,先输出一个整数,表示该解的序号(从1开始),接着输出一个6x6的字母方阵,表示该解。 解的字母之间用空格分开。 如果找不到任何满足条件的解,则输出“无解” 例如:用户输入:
000011
022013
221113
243333
244455
445555
6
02C
03B
05A
20D
35E
53F 则程序输出:
1
E F C B D A
A C E D F B
D A B E C F
F B D C A E
B D F A E C
C E A F B D 再如,用户输入:
001111
002113
022243
022443
544433
555553
7
04B
05A
13D
14C
24E
50C
51A
则程序输出:
1
D C E F B A
E F A D C B
A B F C E D
B E D A F C
F D C B A E
C A B E D F
2
D C E F B A
E F A D C B
A D F B E C
B E C A F D
F B D C A E
C A B E D F
3
D C F E B A
A E B D C F
F D A C E B
B F E A D C
E B C F A D
C A D B F E
4
D C F E B A
B E A D C F
A D C F E B
F B E A D C
E F B C A D
C A D B F E
5
D C F E B A
E F A D C B
A B C F E D
B E D A F C
F D B C A E
C A E B D F
6
D C F E B A
E F A D C B
A B D F E C
B E C A F D
F D B C A E
C A E B D F
7
D C F E B A
E F A D C B
A D B F E C
B E C A F D
F B D C A E
C A E B D F
8
D C F E B A
F E A D C B
A D B C E F
B F E A D C
E B C F A D
C A D B F E
9
D C F E B A
F E A D C B
A F C B E D
B D E A F C
E B D C A F
C A B F D E
package com.liu.ex9; import java.util.HashSet;
import java.util.Scanner; public class Main {
public static int[][] group = new int[6][6]; //输入分组情况
public static char[][] result = new char[6][6]; //满足题意的填充结果
public static int[][] row = new int[6][6]; //检测6行是否均为不同字母
public static int[][] col = new int[6][6]; //检测6列是否均为不同字母
public static int[][] set = new int[6][6]; //检测0~5组是否均为不同字母
public static char[] value = {'A','B','C','D','E','F'}; //填充字母
public static int count = 0; //统计最终解个数
public HashSet<String> hash = new HashSet<String>(); public boolean check() {
StringBuilder temp = new StringBuilder("");
for(int i = 0;i < 6;i++) {
for(int j = 0;j < 6;j++)
temp.append(result[i][j]+" ");
temp.append("\n");
}
String A = temp.toString();
if(hash.contains(A))
return false;
return true;
} public void dfs(int step) {
if(step >= 37) {
if(check()) { //检测是否有重复解
count++;
System.out.println(count);
StringBuilder temp = new StringBuilder("");
for(int i = 0;i < 6;i++) {
for(int j = 0;j < 6;j++)
temp.append(result[i][j]+" ");
temp.append("\n");
}
hash.add(temp.toString());
System.out.print(temp);
}
return;
} else {
int tempRow = (step - 1) / 6;
int tempCol = (step - 1) % 6;
int tempSet = group[tempRow][tempCol];
for(int i = 0;i < 6;i++) {
if(result[tempRow][tempCol] == '-') {
char temp = (char) ('A' + i);
if(row[tempRow][i] == 0 && col[tempCol][i] == 0 && set[tempSet][i] == 0) {
result[tempRow][tempCol] = temp;
row[tempRow][i] = 1;
col[tempCol][i] = 1;
set[tempSet][i] = 1;
dfs(step + 1);
result[tempRow][tempCol] = '-'; //回溯处理
row[tempRow][i] = 0;
col[tempCol][i] = 0;
set[tempSet][i] = 0; } else {
continue;
}
} else {
dfs(step + 1);
}
}
}
return;
} public static void main(String[] args) {
Main test = new Main();
for(int i = 0;i < 6;i++)
for(int j = 0;j < 6;j++)
result[i][j] = '-'; //初始化为填充格子字符为'-'
Scanner in = new Scanner(System.in);
for(int i = 0;i < 6;i++) {
String temp = in.nextLine();
for(int j = 0;j < 6;j++)
group[i][j] = temp.charAt(j) - '0';
}
int n = in.nextInt();
in.nextLine();
for(int i = 0;i < n;i++) {
String temp = in.nextLine();
int a = temp.charAt(0) - '0';
int b = temp.charAt(1) - '0';
int v = temp.charAt(2) - 'A';
result[a][b] = temp.charAt(2);
row[a][v] = 1; //表示第a行位于第v个的位置,已经填充
col[b][v] = 1; //表示第b列位于第v个的位置,已经填充
int tempSet = group[a][b]; //获取(a,b)小组组号
set[tempSet][v] = 1; //表示第tempSet小组第v个位置,已经填充
}
test.dfs(1);
}
}
10 立方和等式
考虑方程式:a^3 + b^3 = c^3 + d^3
其中:“^”表示乘方。a、b、c、d是互不相同的小于30的正整数。
这个方程有很多解。比如:
a = 1,b=12,c=9,d=10 就是一个解。因为:1的立方加12的立方等于1729,而9的立方加10的立方也等于1729。
当然,a=12,b=1,c=9,d=10 显然也是解。
如果不计abcd交换次序的情况,这算同一个解。
你的任务是:找到所有小于30的不同的正整数解。把a b c d按从小到大排列,用逗号分隔,每个解占用1行。比如,刚才的解输出为:
1,9,10,12 不同解间的顺序可以不考虑。
package com.liu.ex10; import java.util.ArrayList;
import java.util.Collections; public class Main { public static boolean judge(ArrayList<Integer> tempList) {
ArrayList<Integer> list = new ArrayList<Integer>();
for(int i = 0;i < tempList.size();i++)
list.add(tempList.get(i));
Collections.sort(list);
for(int i = 1;i < list.size();i++) {
if(list.get(i - 1) == list.get(i))
return false;
}
return true;
} public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
for(int a = 1;a < 30;a++) {
for(int b = 1;b < 30;b++) {
for(int c = 1;c < 30;c++) {
for(int d = 1;d < 30;d++) {
ArrayList<Integer> tempList = new ArrayList<Integer>();
tempList.add(a);
tempList.add(b);
tempList.add(c);
tempList.add(d);
if(judge(tempList) == true) {
if(a*a*a + b*b*b == c*c*c + d*d*d) {
Collections.sort(tempList);
String A = ""+tempList.get(0)+","+tempList.get(1)+","+tempList.get(2)+","+tempList.get(3);
if(!list.contains(A))
list.add(A);
}
}
}
}
}
} for(int i = 0;i < list.size();i++)
System.out.println(list.get(i));
}
}
算法笔记_125:算法集训之编程大题集一(Java)的更多相关文章
- 算法笔记_126:算法集训之编程大题集二(Java)
目录 1 连续数的公倍数 2 漏掉的账目明细 3 罗马数字转十进制 4 逻辑推断 5 平面4点最小距离 6 取球博弈 7 人民币金额大写 8 人员排日程 9 三角螺旋阵 10 手机尾号评分 1 ...
- 【收藏】Java多线程/并发编程大合集
(一).[Java并发编程]并发编程大合集-兰亭风雨 [Java并发编程]实现多线程的两种方法 [Java并发编程]线程的中断 [Java并发编程]正确挂起.恢复.终止线程 [ ...
- 学习Java 以及对几大基本排序算法(对算法笔记书的研究)的一些学习总结(Java对算法的实现持续更新中)
Java排序一,冒泡排序! 刚刚开始学习Java,但是比较有兴趣研究算法.最近看了一本算法笔记,刚开始只是打算随便看看,但是发现这本书非常不错,尤其是对排序算法,以及哈希函数的一些解释,让我非常的感兴 ...
- 算法笔记_119:蓝桥杯第六届省赛(Java语言A组)试题解答
目录 1 熊怪吃核桃 2 星系炸弹 3 九数分三组 4 循环节长度 5 打印菱形 6 加法变乘法 7 牌型种数 8 移动距离 9 垒骰子 10 灾后重建 前言:以下试题解答代码部分仅供参考,若有 ...
- 算法笔记_041:寻找和为定值的多个数(Java)
目录 1 问题描述 2 解决方案 1 问题描述 输入两个整数n和sum,要求从数列1,2,3,...,n中随意取出几个数,使得它们的和等于sum,请将其中所有可能的组合列出来. 2 解决方案 上述问题 ...
- 算法笔记_165:算法提高 道路和航路(Java)
目录 1 问题描述 2解决方案 1 问题描述 问题描述 农夫约翰正在针对一个新区域的牛奶配送合同进行研究.他打算分发牛奶到T个城镇(标号为1..T),这些城镇通过R条标号为(1..R)的道路和P条 ...
- 【Java并发编程】并发编程大合集-值得收藏
http://blog.csdn.net/ns_code/article/details/17539599这个博主的关于java并发编程系列很不错,值得收藏. 为了方便各位网友学习以及方便自己复习之用 ...
- 【Java并发编程】并发编程大合集
转载自:http://blog.csdn.net/ns_code/article/details/17539599 为了方便各位网友学习以及方便自己复习之用,将Java并发编程系列内容系列内容按照由浅 ...
- 算法笔记_116:算法集训之代码填空题集三(Java)
目录 1 数组转置 2 文件管理 3 显示为树形 4 杨辉三角系数 5 圆周率与级数 6 整数翻转 7 自行车行程 8 祖冲之割圆法 9 最大5个数 10 最大镜像子串 1 数组转置 编写程序将 ...
随机推荐
- JavaScript RegExp对象的exec()方法
JavaScript RegExp对象的exec()方法用来匹配字符串,它的行为与match()有些不同. 对于RegExpObject.exec(),w3school上面是这样介绍的: exec() ...
- Linux 内核编译步骤及配置详解
前言 Linux内核是操作系统的核心,也是操作系统最基本的部分. Linux内核的体积结构是单内核的.但是他充分采用了微内核的设计思想.使得虽然是单内核.但工作在模块化的方式下.并且这个模块可以 ...
- Spring @Value 用法小结,#与$的区别
20161016更新:这货其实是SpEL的功能,来这里看看吧: Spring 4 官方文档学习(五)核心技术之SpEL 起因 一直的用法是 @Value("${jdbc.driverClas ...
- 解决firefox不支持innerText的办法
js代码: <script> window.onload = function(){ if(window.navigator.userAgent.toLowerCase().indexOf ...
- mysql 3.2.49 源代码安装-redhat 5 x64
[mysql@localhost ~]$ uname -r2.6.32 [root@localhost ~]#cp /usr/include/pthread.h /usr/include/pthrea ...
- Access-Control-Allow-Origin,跨域
1.浏览器的同源安全策略 浏览器只允许请求当前域的资源,而对其他域的资源表示不信任.那怎么才算跨域呢? 请求协议http,https的不同 域domain的不同 端口port的不同 好好好,大概就是这 ...
- 优化中的subgradient方法
哎.刚刚submit上paper比較心虚啊.无心学习.还是好好码码文字吧. subgradient介绍 subgradient中文名叫次梯度.和梯度一样,全然能够多放梯度使用.至于为什么叫子梯度,是由 ...
- Bootstrap 3之美03-独立行,文字环绕,图片自适应,隐藏元素
本篇主要包括: ■ 添加独立的一行■ 文字环绕■ 图片自适应■ 隐藏元素 添加独立的一行 在id为body的section和id为main的section之间,添加2张图片. 我们发现,新加的 ...
- windowsmobile 开发环境
Windows Mobile 6开发环境的配置过程 需要的文件列表:1.Visual Studio 2005 Professional及更高的版本(Visual Studio 2005 Express ...
- FastJson和Gson和Json数据解析分析和用法
首先分析下目前号称最快的FastJson,这个是所有人都验证过的,解析速度确实比较快,不过也需要根据数据量来看,数据量小的时候,Gson性能要稍微优于FastJson,但在数据量大解析的情况下,Fas ...