第一次上机练习
习题B:曹冲称象
Input:
The input contains several test cases. Each test cases consists of a number N integers, indicate each stone’s weight.
For you attention:each of stone’s weight will be no more than 100.
Ouput:
For each case, output the elephant’s weight.
Sample Input:
5
2 4 3 1 5
3
100 100 100
Sample Output:
15
300
Codeing:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int num = scanner.nextInt();
int input[] = new int[num];
int sum = 0;
for (int i = 0; i < num; i++) {
input[i] = scanner.nextInt();
sum = sum + input[i];
}
System.out.println(sum);
}
}
}
习题C:平方和问题
description:
Some integers can be expressed by square sum of other integers.
For example:
25=12+22+22+42
25=32+42
25=52
So there are 3 ways to express 25 can be expressed?
In the problem a integer can be expressed by four integers square sum at most. Pay attention change order is same way. For example, the way 32+42.
Input:
The first line is the number of cases, a integer T).
For each sample, there are only one line and the line is only one integer N(1≤N≤215).
Ouput:
Print the answer of each sample.
Sample Input:
1
25
Sample Output:
3
Codeing:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int num = scanner.nextInt();//测试数据的样例数
for(int i = 0; i < num; i++){
int cases = 0;//样例的情况数
int digit = scanner.nextInt();
int digitSqrt = (int) Math.sqrt(digit);
for (int j = 0; j <= digitSqrt; j++) {
for (int k = j; k <= digitSqrt; k++) {
for (int l = k; l <= digitSqrt; l++) {
int m = digit - (j * j + k * k + l * l);
int n = (int) Math.floor(Math.sqrt(m));//取Math.sqrt(m)接近的但小于Math.sqrt(m)的整数
if ((n * n== m) && n >= l) {
cases++;
}
}
}
}
System.out.println(cases);
}
}
}
第二次上机练习
习题A:另一个Fibonacci数列
Description:
定义另外一个Fibonacci数列:F(0)=7,F(1)=11,F(n)=F(n-1)+F(n-2),(n≥2)。
Input:
输入文件中包含多行,每行为一个整数n,n<1000000。
Ouput:
对输入文件中的每个整数n,如果F(n)能被3整除,输出yes,否则输出no。
Sample Input:
0
1
2
3
Sample Output:
15
300
Codeing:
import java.util.Scanner;
public class Main {
static int Fibonacci(int num){
if(num < 0){
return -1;//代表错误输入
}else if(num == 0){
return 7;
}else if(num == 1){
return 11;
}else{
return Fibonacci(num - 1) + Fibonacci(num - 2);
}
}
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()){
int input = scanner.nextInt();
int fibonacci = Fibonacci(input);
if(fibonacci%3 == 0){
System.out.println("yes");
}else{
System.out.println( "no");
}
}
}
}
习题C:波兰表达式
Description:
波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的波兰表示法为+ 2 3。波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的波兰表示法为* + 2 3 4。本题求解波兰表达式的值,其中运算符包括+ - * /四个。
Input:
输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数。
Ouput:
输出为一行,表达式的值。
可直接用printf(“%f\n”, v)输出表达式的值v。
Sample Input:
* + 11.0 12.0 + 24.0 35.0
Sample Output:
1357.000000
Codeing:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in
);
Stack stack = new Stack();
List<Float> list = new ArrayList<Float>();
while(scanner.hasNext()) {
String s = scanner.nextLine();
if(s.equals(";")) {
break;
}
String[] array = s.split(" ");
int length = array.length;
for (int i = length - 1; i >= 0; i--) {
if (array[i].equals("+")) {
float a = Float.parseFloat((String) stack.pop());
float b = Float.parseFloat((String) stack.pop());
float c = a + b;
String temp = String.valueOf(c);
stack.push(temp);
continue;
}
if (array[i].equals("-")) {
float a = Float.parseFloat((String) stack.pop());
float b = Float.parseFloat((String) stack.pop());
float c = a - b;
String temp = String.valueOf(c);
stack.push(temp);
continue;
}
if (array[i].equals("*")) {
float a = Float.parseFloat((String) stack.pop());
float b = Float.parseFloat((String) stack.pop());
float c = a * b;
String temp = String.valueOf(c);
stack.push(temp);
continue;
}
if (array[i].equals("/")) {
float a = Float.parseFloat((String) stack.pop());
float b = Float.parseFloat((String) stack.pop());
float c = a / b;
String temp = String.valueOf(c);
stack.push(temp);
continue;
}
stack.push(array[i]);
}
float result = Float.parseFloat((String) stack.pop());
list.add(result);
}
for(int i = 0; i < list.size(); i++) {
System.out.printf("%f\n", list.get(i));
}
}
}
习题D:放苹果
Description:
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法(用K表示)?注意:5,1,1和1,5,1 是同一种分法。
Input:
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
Ouput:
对输入的每组数据M和N,用一行输出相应的K。
Sample Input:
1
7 3
Sample Output:
8
Codeing:
import java.util.Scanner;
public class Main {
static int sortOut(int apple,int boxes){
if( boxes == 0){//没有箱子
return 0;
}else if(apple == 1 || boxes == 1){//只有一个苹果或一个箱子
return 1;
}else if(apple < boxes){//至少有一个盘子为空,撤去空盘子数量不改变
return sortOut(apple,boxes-1);
}else {
/*
情况:苹果数和盘子数相等,或苹果数大于盘子数
处理:分为放满和不放满,放满:sortOut(apple-boxes,boxes),不放满:sortOut(apple-boxes,boxes)
*/
return sortOut(apple,boxes-1)+sortOut(apple-boxes,boxes);
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int num =scanner.nextInt();//测试样例数
for(int i = 0; i < num; i++){
int apple = scanner.nextInt();
int boxes = scanner.nextInt();
System.out.println(sortOut(apple,boxes));
}
}
}
习题E:满二叉树
Description:
由正整数1, 2, 3, …组成了一棵无限大的满二叉树,二叉树中的每个节点按照从上到下,从左到右的顺序从1开始编号。从某一个结点到根结点(编号是1的结点)都有一条唯一的路径,比如从10到根结点的路径是(10, 5, 2, 1),从4到根结点的路径是(4, 2, 1),从根结点1到根结点的路径上只包含一个结点1,因此路径就是(1)。对于两个结点x和y,假设他们到根结点的路径分别是(x1, x2, … ,1)和(y1, y2, … ,1)(这里显然有x = x1,y = y1),那么必然存在两个正整数i和j,使得从xi 和 yj开始,有xi = yj , xi + 1 = yj + 1, xi + 2 = yj + 2,… 现在的问题就是,给定x和y,要求xi(也就是yj)。
Input:
输入只有一行,包括两个正整数x和y,这两个正整数都不大于1000。
Ouput:
输出只有一个正整数xi。
Sample Input:
10 4
Sample Output:
2
Codeing:
import java.util.Scanner;
public class Main {
static int binaryTree(int node1,int node2){
if(node1 < 1 || node2 < 1){
return 0;
}else if(node1 == node2){//两节点数相等
return node1;
}else if(node1 <= 3 && node2 <= 3){//两节点数均小于3
return 1;
}else if(node1 > node2){//node1 > node2
if(node1 % 2 != 0){//奇数
return binaryTree((node1-1)/2,node2);
}else//偶数
return binaryTree(node1/2,node2);
}else if(node1 < node2){//node1 < node2
if(node2 % 2 != 0){//奇数
return binaryTree(node1,(node2-1)/2);
}else//偶数
return binaryTree(node1,node2/2);
}
return 0;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()){
int node1 = scanner.nextInt();
int node2 = scanner.nextInt();
System.out.println(binaryTree(node1,node2));
}
}
}
第三次上机练习
习题A:大整数乘法
Description:
求两个不超过200位的非负整数的积。
Input:
有两行,每行是一个不超过200位的非负整数,没有多余的前导0。
Ouput:
一行,即相乘后的结果。结果里不能有多余的前导0,即如果结果是342,那么就不能输出为0342。
Sample Input:
12345678900
98765432100
Sample Output:
1219326311126352690000
Codeing:
#include<stdio.h>
#include<string.h>
int main()
{
int r[401]={0};
char n1[201]={'\0'}, n2[201]={'\0'};
while(~scanf("%s%s",n1,n2)){
memset(r,0,sizeof(r));
int len1=strlen(n1), len2=strlen(n2);
int i, j, k;
for(i=len1-1;i>=0;--i)
{
for(j=len2-1;j>=0;--j)
{
r[len1+len2-2-i-j]+=(n1[i]-'0')*(n2[j]-'0');
}
for(k=0;k<len1+len2-1;++k)
{
if(r[k]>9)
{
r[k+1]+=r[k]/10;
r[k]%=10;
}
}
}
int n=len1+len2-1;
if(r[n]==0)
--n;
for(i=n;i>=0;--i)
printf("%d",r[i]);
memset(n1,0,sizeof(n1));
memset(n2,0,sizeof(n2));
}
return 0;
}
习题B:赌徒
Description:
N个赌徒一起决定玩一个游戏:
游戏刚开始的时候,每个赌徒把赌注放在桌上并遮住,侍者要查看每个人的赌注并确保每个人的赌注都不一样。如果一个赌徒没钱了,则他要借一些筹码,因此他的赌注为负数。假定赌注都是整数。
最后赌徒们揭开盖子,出示他们的赌注。如果谁下的赌注是其他赌徒中某3个人下的赌注之和,则他是胜利者。如果有多于一个胜利者,则下的赌注最大的赌徒才是最终的胜利者。
例如,假定赌徒为:Tom、Bill、John、Roger和Bush,他们下的赌注分别为:¥2、¥3、¥5、¥7和¥12 。因此最终获胜的是Bush(并且没有其他人是胜利者),因为他下的赌注为¥12,而其他的人下的赌注之和也等于12:¥2+¥3+¥7=¥12。
Input:
输入文件中包含了多组赌徒下的赌注。每组赌注的数据第1行是一个整数n,1<=n<=1000,代表赌徒的个数,然后是他们下的赌注,每个人的赌注占一行,这些赌注各不相同,并且范围是[-536870912,+536870911]。输入文件的最后一行为0,代表输入结束。
Ouput:
对每组赌注,输出胜利者下的赌注,如果没有解,则输出“no solution”。
Sample Input:
5
2
3
5
7
12
5
2
16
64
256
1024
0
Sample Output:
12
no solution
Codeing:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
while(input.hasNext()) {
int n = input.nextInt();
if(n == 0)
break;
int[] duzhu = new int[n];
for(int i = 0; i < n; i++)
duzhu[i] = input.nextInt();
if(n <= 3) {
System.out.println("no solution");
continue;
}
Arrays.sort(duzhu);
boolean findResult = false;
int result = 0;
for(int i = n - 1; i >= 0; i--) {
for(int j = 0; j < i; j++) {
for(int k = j + 1; k < i; k++) {
int temp = duzhu[i] - duzhu[j] - duzhu[k];
int r = binarySearch(k + 1, i - 1, duzhu, temp);
if(r != -1) {
findResult = true;
result = duzhu[i];
break;
}
}
if(findResult)
break;
}
if(findResult)
break;
}
if(findResult)
System.out.println(result);
else
System.out.println("no solution");
}
}
public static int binarySearch(int low, int high, int[] src, int target) {
while(low <= high) {
int mid = (low + high) / 2;
if(src[mid] == target)
return mid;
if(src[mid] < target)
low = mid + 1;
else
high = mid - 1;
}
return -1;
}
}
习题C:半素数
Description:
素数的定义:对于一个大于1的正整数,如果除了1和它本身没有其他的正约数了,那么这个数就称为素数。例如,2,11,67,89是素数,8,20,27不是素数。
半素数的定义:对于一个大于1的正整数,如果它可以被分解成2个素数的乘积,则称该数为半素数,例如6是一个半素数,而12不是。
你的任务是判断一个数是否是半素数。
Input:
输入文件中有多个测试数据,每个测试数据包含一个整数N,2<=N<=1,000,000。
Ouput:
对每个测试数据,如果N是半素数,则输出YES,否则输出NO。
Sample Input:
3
4
6
12
Sample Output:
No
Yes
Yes
No
Codeing:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int[] array = findPrime(1000000);
Scanner scanner = new Scanner(System.in
);
while(scanner.hasNext()) {
int n = scanner.nextInt();
if(n == -1) {
return;
}
solution(n, array);
}
}
public static void solution(int n, int[] array) {
for(int i = 0; i < array.length; i++) {
int j = n / array[i];
if(j * array[i] == n && binarySearch(array, j) == j) {
System.out.println("Yes");
return;
}
}
System.out.println("No");
}
public static int[] findPrime(int n) {
boolean[] judge = new boolean[n + 1];
for(int i = 1; i <= n; i++) {
if(i % 2 != 0) {
judge[i] = true;
}
}
judge[0] = judge[1] = false;
judge[2] = true;
int count = 0;
for(int i = 3; i <= Math.sqrt(n); i++) {
if(judge[i] == true) {
for(int j = i * 2; j <= n; j += i) {
judge[j] = false;
}
}
}
for(int i = 0; i < judge.length; i++) {
if(judge[i] == true) {
count++;
}
}
int[] array = new int[count];
count = 0;
for(int i = 2; i < judge.length; i++) {
if(judge[i] == true) {
array[count++] = i;
}
}
return array;
}
// 二分查找
public static int binarySearch(int[] array, int target) {
int left = 0;
int right = array.length - 1;
int mid = 0;
while(left <= right) {
mid = (left + right) / 2;
if(array[mid] == target) {
return target;
}
if(array[mid] > target) {
right = mid - 1;
}
if(array[mid] < target) {
left = mid + 1;
}
}
return -1;
}
}
第四次上机练习
习题A:最长上升子序列
Description:
一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < …
Input:
输入包含多组数据,每组数据的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。
Ouput:
最长上升子序列的长度。
Sample Input:
7
1 7 3 5 9 4 8
Sample Output:
4
Codeing:
import java.util.Scanner;
public class Main {
public static int replace(int[] temp, int begin, int end, int key) {
if(temp[end] <= key) {
return end + 1;
}
int mid = 0;
while(begin < end) {
mid = (begin + end) / 2;
if(temp[mid] <= key) {
begin = mid + 1;
}else {
end = mid;
}
}
return begin;
}
public static int function(int[] array) {
int length = array.length;
int[] temp = new int[length];
int result = 1;
int index = 0;
temp[0] = array[0];
for(int i = 1; i < length; i++) {
index = replace(temp, 0, result - 1, array[i]);
temp[index] = array[i];
if(result <= index + 1) {
result = index + 1;
}
}
return result;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()) {
int n = scanner.nextInt();
if(n == -1) {
break;
}
int[] array = new int[n];
for(int i = 0; i < n; i++) {
array[i] = scanner.nextInt();
}
System.out.println(function(array));
}
}
}
习题B:最长公共子序列
Description:
我们称序列Z = < z1, z2, …, zk >是序列X = < x1, x2, …, xm >的子序列当且仅当存在严格上升的序列< i1, i2, …, ik >,使得对j = 1, 2, … ,k, 有xij = zj。比如Z = < a, b, f, c > 是X = < a, b,c, f, b, c >的子序列。
现在给出两个序列X和Y,你的任务是找到X和Y的最大公共子序列,也就是说要找到一个最长的序列Z,使得Z既是X的子序列也是Y的子序列。
Input:
输入包括多组测试数据。每组数据包括一行,给出两个长度不超过200的字符串,表示两个序列。两个字符串之间由若干个空格隔开。
Ouput:
对每组输入数据,输出一行,给出两个序列的最大公共子序列的长度。
Sample Input:
abcfbc abfcab
programming contest
abcd mnp
Sample Output:
4
2
0
Codeing:
import java.util.List;
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
List list = new ArrayList();
while(scanner.hasNext()) {
String s = scanner.nextLine();
if(s.equals("-1")) {
break;
}
s = s.replace('\t', ' ');
int begin = s.indexOf(" ");
int end = s.lastIndexOf(" ");
String s1 = s.substring(0, begin);
String s2 = s.substring(end + 1, s.length());
char[] a = s1.toCharArray();
char[] b = s2.toCharArray();
list.add(solution(a, b));
}
for(int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
public static int solution(char[] a, char[] b) {
int m = a.length;
int n = b.length;
int[][] c = new int[m + 1][n + 1];
for(int i = 1; i <= m; i++) {
c[i][0] = 0;
}
for(int j = 1; j <= n; j++) {
c[0][j] = 0;
}
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(a[i] == b[j]) {
c[i + 1][j + 1] = c[i][j] + 1;
}
else if(c[i + 1][j] >= c[i][j + 1]) {
c[i + 1][j + 1] = c[i + 1][j];
}
else {
c[i + 1][j + 1] = c[i][j + 1];
}
}
}
return c[m][n];
}
}
习题C:租用游艇
Description:
长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i
Input:
输入数据的第一行中有1个正整数n(n<=200),表示有n个游艇出租站,接下来的n-1行是r(i,j),1<=i
Ouput:
输出从游艇出租站1到游艇出租站n所需要的最少租金。
Sample Input:
3
5 15
7
Sample Output:
12
Codeing:
import java.util.Scanner;
public class Main {
public static int function(int[][] rent, int n) {
int[][] best = new int[n + 1][n + 1];
for(int i = n - 1; i >= 1; i--) {
best[i][n] = rent[i][n];
for(int j = n - 1; j > i; j--) {
best[i][n] = Math.min(rent[i][j] + best[j][n], best[i][n]);
}
}
return best[1][n];
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[][] rent = new int[n + 1][n + 1];
for(int i = 1; i < n; i++) {
for(int j = i + 1; j <= n; j++) {
rent[i][j] = scanner.nextInt();
}
}
System.out.println(function(rent, n));
}
}
第五次上机练习
习题A:木棒问题
Description:
现有n根木棒,已知它们的长度和重量。要用一部木工机一根一根地加工这些木棒。该机器在加工过程中需要一定的准备时间,是用于清洗机器,调整工具和模板的。木工机需要的准备时间如下:
(1) 第一根木棒需要1min的准备时间;
(2) 在加工了一根长为l,重为w的木棒之后,接着加工一根长为l’(l≤l’),重为w’(w≤w’)的木棒是不需要任何准备时间的。否则需要一分钟的准备时间。
给定n根木棒,你要找到最少的准备时间。例如现在有长和重分别为(4,9),(5,2),(2,1),(3,5)和(1,4)的五根木棒,那么所需准备时间最少为2min,顺序为(1,4),(3,5),(4,9),(2,1),(5,2)。
Input:
输入有多组测试例。输入数据的第一行是测试例的个数(T)。每个测试例两行:第一行是一个整数n(1≤n≤5000),表示有多少根木棒;第二行包括n*2个整数,表示l1,w1,l2,w2,l3,w3,…,ln,wn,全部不大于10000,其中li和wi表示第i根木棒的长度和重量。数据由一个或多个空格分隔。
Ouput:
输出是以分钟为单位的最少准备时间,一行一个。
Sample Input:
3
5
4 9 5 2 2 1 3 5 1 4
3
2 2 1 1 2 2
3
1 3 2 2 3 1
Sample Output:
2
1
3
Codeing:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
List list = new ArrayList();
int n = scanner.nextInt();
for(int i = 0; i < n; i++) {
int count = scanner.nextInt();
List<Mood> temp = new ArrayList<Mood>();
for(int j = 0; j < count; j++) {
Mood mood = new Mood();
mood.length = scanner.nextInt();
mood.weight = scanner.nextInt();
temp.add(mood);
}
list.add(solution(temp));
}
for(int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
public static int solution(List<Mood> list) {
Collections.sort(list, new Comparator<Mood>() {
@Override
public int compare(Mood o1, Mood o2) {
return o1.length - o2.length;
}
});
if(list == null && list.size() <= 0) {
return -1;
}
boolean[] flag = new boolean[list.size()];
Mood old = null;
Mood now = null;
int count = 0;
while(check(flag)) {
for(int i = 0; i < list.size(); i++) {
if(flag[i] == true) {
continue;
}
now = list.get(i);
if(old == null) {
flag[i] = true;
old = list.get(i);
continue;
}
if(now.weight >= old.weight && now.length >= old.length) {
flag[i] = true;
old = list.get(i);
}
}
old = now =null;
count++;
}
return count;
}
public static boolean check(boolean[] flag) {
for(int i = 0; i < flag.length; i++) {
if(flag[i] == false) {
return true;
}
}
return false;
}
}
class Mood {
int length;
int weight;
}
习题B:装箱问题
Description:
个工厂制造的产品形状都是长方体,它们的高度都是h,长和宽都相等,一共有六个型号,他们的长宽分别为1*1, 2*2, 3*3, 4*4, 5*5, 6*6。这些产品通常使用一个 6*6*h 的长方体包裹包装然后邮寄给客户。因为邮费很贵,所以工厂要想方设法的减小每个订单运送时的包裹数量。他们很需要有一个好的程序帮他们解决这个问题从而节省费用。现在这个程序由你来设计。
Input:
输入文件包括几行,每一行代表一个订单。每个订单里的一行包括六个整数,中间用空格隔开,分别为1*1至6*6这六种产品的数量。输入文件将以6个0组成的一行结尾。
Ouput:
除了输入的最后一行6个0以外,输入文件里每一行对应着输出文件的一行,每一行输出一个整数代表对应的订单所需的最小包裹数。
Sample Input:
0 0 4 0 0 1
7 5 1 0 0 0
0 0 0 0 0 0
Sample Output:
2
1
Codeing:
import java.io.BufferedInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Main{
public static void main(String args[]) {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
boolean flag = true;
Map map = new HashMap();
int k = 0;
while (flag) {
int n[] = new int[6];
n[0] = sc.nextInt();
n[1] = sc.nextInt();
n[2] = sc.nextInt();
n[3] = sc.nextInt();
n[4] = sc.nextInt();
n[5] = sc.nextInt();
if (n[0] == 0 && n[1] == 0 && n[2] == 0 && n[3] == 0 && n[4] == 0 && n[5] == 0) {
flag = false;
} else {
map.put(k, n);
k++;
}
}
for (int i = 0; i < map.size(); i++) {
int[] vs = (int[]) map.get(i);
int boxNum = 0;
boxNum += vs[3] + vs[4] + vs[5];
if (vs[2] > 0) {
if (vs[2] % 4 == 0) {
boxNum += vs[2] / 4;
} else {
boxNum += vs[2] / 4 + 1;
}
}
int for1 = vs[4] * 11;
int for2 = vs[3] * 5;
if (vs[2] % 4 == 1) {
for1 += 7;
for2 += 5;
} else if (vs[2] % 4 == 2) {
for1 += 6;
for2 += 3;
} else if (vs[2] % 4 == 3) {
for1 += 5;
for2 += 1;
}
if (vs[0] < for1) {
vs[0] = 0;
} else {
vs[0] = vs[0] - for1;
}
if (vs[1] < for2) {
if (vs[0] > 0) {
if (4 * (for2 - vs[1]) - vs[0] >= 0) {
vs[0] = 0;
} else {
vs[0] = vs[0] - 4 * (for2 - vs[1]);
}
}
vs[1] = 0;
} else {
vs[1] = vs[1] - for2;
}
if (!(vs[0] == 0 && vs[1] == 0)) {
if (vs[1] > 0) {
if (vs[1] % 9 == 0) {
boxNum += vs[1] / 9;
} else {
boxNum += vs[1] / 9 + 1;
if (vs[0] > (9 - (vs[1] % 9)) * 4) {
if ((vs[0] - (9 - (vs[1] % 9)) * 4) % 36 == 0) {
boxNum += (vs[0] - (9 - (vs[1] % 9)) * 4) / 36;
} else {
boxNum += (vs[0] - (9 - (vs[1] % 9)) * 4) / 36 + 1;
}
}
}
} else if (vs[0] > 0) {
if (vs[0] % 36 == 0) {
boxNum += vs[0] / 36;
} else {
boxNum += vs[0] / 36 + 1;
}
}
}
System.out.println(boxNum);
}
}
}
习题B:移动桌子
Description:
著名的ACM(Advanced Computer Maker)公司租用了一层有400个房间的办公楼,结构如下。
这层楼沿着走廊南北向的两边各有200个房间。最近,公司要做一次装修,需要在各个办公室之间搬运办公桌。由于走廊狭窄,办公桌都很大,走廊里一次只能通过一张办公桌。必须制定计划提高搬运效率。经理制定如下计划:一张办公桌从一个房间移动到另一个房间最多用十分钟。当从房间i移动一张办公桌到房间j,两个办公室之间的走廊都会被占用。所以,每10分钟内,只要不是同一段走廊,都可以在房间之间移动办公桌。为了说得更清楚一些,经理举例说明哪些情况可以同时移动,哪些情况不能同时移动。
每个房间,只有一张办公桌进出。现在,经理想找到一种方案,使移动桌子的事情尽快完成。请编写程序解决经理的难题。
Input:
输入数据有T组测试例,在第一行给出测试例个数(T)。每个测试例的第一行是一个整数N(1≤N≤200),表示要搬运办公桌的次数。接下来N行,每行两个正整数s和t,表示一张桌子,是从房间号码s移到房间号码t。有多组输入数据,输入第一行为一个表示输入数据总数的整数N,然后是N组输入数据。
Ouput:
每组输入都有一行的输出数据,为一整数T,表示完成任务所花费的最少时间。
Sample Input:
3
4
10 20
30 40
50 60
70 80
2
1 3
2 200
3
10 100
20 80
30 50
Sample Output:
10
20
30
Codeing:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in );
List list = new ArrayList();
int n = scanner.nextInt();
for(int i = 0; i < n; i++) {
List<Room> temp = new ArrayList<>();
int count = scanner.nextInt();
for(int j = 0; j < count; j++) {
Room room = new Room();
room.begin = scanner.nextInt();
room.end = scanner.nextInt();
temp.add(room);
}
list.add(solution(temp));
}
for(int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
public static int solution(List<Room> list) {
Collections.sort(list, new Comparator<Room>() {
public int compare(Room o1, Room o2) {
return o1.begin - o2.begin;
}
});
boolean[] flag = new boolean[list.size()];
int count = 0;
int head = 0;
int tail = 0;
while(check(flag)) {
for(int i = 0; i < list.size(); i++) {
if(flag[i] == true) {
continue;
}
head = list.get(i).begin;
if(tail == 0) {
flag[i] = true;
tail = list.get(i).end;
continue;
}
if(head > tail) {
flag[i] = true;
tail = list.get(i).end;
continue;
}
}
head = 0;
tail = 0;
count++;
}
return count * 10;
}
public static boolean check(boolean[] flag) {
for(int i = 0; i < flag.length; i++) {
if(flag[i] == false) {
return true;
}
}
return false;
}
}
class Room {
int begin;
int end;
}
第六次上机练习
习题A:子集和问题
Description:
子集和问题的一个实例为<S,t>
。其中,S={x1,x2,…,xn}是一个正整数的集合,c是一个正整数。子集和问题判定是否存在S的一个子集S1,使得∑x∈S1x=c
Input:
输入数据文件第1行有2个正整数n和c,n表示S的大小,c是子集和.的目标值。接下来的1行中,有n个正整数,表示集合S中的元素.
Ouput:
将子集和问题的解输出,当问题无解时,输出No solution!
Sample Input:
5 10
2 2 6 5 4
Sample Output:
2 2 6
Codeing:
import java.util.Scanner;
public class Main {
private static int c = 0;
static int S[];
static int X[];
static int CurNum = 0;
static int flag =0;
public static void backtrack(int t){
if (CurNum >= c|| t>=S.length){
if (CurNum == c&& flag==0){
for (int i=0;i<t;i++){
if (X[i]==1){
flag = 1;
if (i<t-1){
System.out.print(S[i]+" ");
}else{
System.out.print(S[i]);
}
}
}
}
}
else {
for (int i=1;i>=0;i--){
X[t]=i;
if (i==0){
backtrack(t+1);
}else {
if (CurNum+S[t]<=c){
CurNum += S[t];
backtrack(t+1);
CurNum -= S[t];
}
}
}
}
}
public static void main(String args[]){
Scanner input = new Scanner(System.in);
int n = input.nextInt();
c = input.nextInt();
S = new int[n];
for (int i=0;i<n;i++){
S[i]=input.nextInt();
}
X = new int[n];
for (int i=0;i<n;i++){
X[i]=0;
}
backtrack(0);
if (flag==0){
System.out.println("No solution!");
}
}
}
习题B:最小重量机器
Description:
设某一机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得。设wij是从供应商j处购得的部件i的重量,cij是相应的价格。试设计一个算法,给出总价格不超过c的最小重量机器设计。
Input:
输入数据第1行有3个正整数n,m和d。接下来的2n行,每行n个数。前n行是c,后n行是w。
Ouput:
输出文件第1行为计算出的最小重量,第二行为每个部件的供应商。
Sample Input:
3 3 4
1 2 3
3 2 1
2 2 2
1 2 3
3 2 1
2 2 2
Sample Output:
4
1 3 1
Codeing:
import java.util.Scanner;
public class Main {
public static int wei = 0;
public static int pri = 0;
public static int min = 0;
public static int target;
public static int m, n;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()) {
n = scanner.nextInt();
if(n == -1) {
break;
}
m = scanner.nextInt();
target = scanner.nextInt();
int[][] price = new int[n][m];
int[][] weight = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
price[i][j] = scanner.nextInt();
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
weight[i][j] = scanner.nextInt();
}
}
for (int i = 0; i < n; i++) {
min += weight[i][0];
}
int[] flag = new int[n];
int[] minSet = new int[n];
solution(price, weight, 0, flag, minSet);
System.out.println(min);
for(int i = 0; i < minSet.length; i++) {
if(i == minSet.length - 1) {
System.out.println(minSet[i] + 1);
}else {
System.out.print(minSet[i] + 1 + " ");
}
}
}
}
public static void solution(int[][] price, int[][] weight, int k, int[] flag, int[] minSet) {
if(pri > target) {
return;
}
if(k == n) {
if(min > wei) {
min = wei;
reverse(flag, minSet);
}
return;
}
for(int i = 0; i < m; i++) {
wei += weight[k][i];
pri += price[k][i];
flag[k] = i;
solution(price, weight, k + 1, flag, minSet);
wei -= weight[k][i];
pri -= price[k][i];
}
}
public static void reverse(int[] a, int[] b) {
for(int i = 0; i < b.length; i++) {
b[i] = a[i];
}
}
}
习题C:运动员最佳匹配
Description:
羽毛球队有男女运动员各n人。给定两个n*n矩阵P和Q。P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势;Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势。由于技术配合和心里状态等各种因素影响,P[i][j]不一定等于Q[i][j]。男运动员i和女运动员j配对组成混合双打的男女双方竞赛优势为P[i][j]* Q[i][j]。设计一个算法,计算男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大。
Input:
输入数据的第1行有1个正整数n(1<=n<=20)。接下来的2n行,每行n个数。前n行是p,后n行是q。
Ouput:
将计算出的男女双方竞赛优势的总和的最大值输出。
Sample Input:
3
10 2 3
2 3 4
3 4 5
2 2 2
3 5 3
4 5 1
Sample Output:
52
Codeing:
import java.util.Scanner;
public class Main {
public static int temp = 0;
public static int max = 0;
public static int n;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
int[][] man = new int[n][n];
int[][] woman = new int[n][n];
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
man[i][j] = scanner.nextInt();
}
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
woman[i][j] = scanner.nextInt();
}
}
int k = 0;
boolean[] flag = new boolean[n];
solution(man, woman, 0, flag);
System.out.println(max);
}
public static void solution(int[][] man, int[][] woman, int k, boolean[] flag) {
if(k == n) {
max = Math.max(max, temp);
return;
}
for(int i = 0; i < n; i++) {
if(!flag[i]) {
flag[i] = true;
temp += man[k][i] * woman[k][i];
solution(man, woman, k + 1, flag);
temp -= man[k][i] * woman[k][i];
flag[i] = false;
}
}
}
}
第七次上机练习
习题A:闪避湖泊
Description:
农夫约翰的农场在最近的一场暴风雨中被水淹没。但保险公司仅根据他得农场中最大的“湖泊”的大小赔偿一个数额。
农场可表示为N行M列的长方形网格,(1≤N≤100,1≤M≤100)。网格中的每个单元或是干的或是被淹没的,且恰有K个单元被水淹没,(1≤K≤N*M)。正如人们所希望的,湖泊是一个中间单元,它与其他的单元共享一条长边(不是角落)。任何与中间单元共享一条长边或者与连通单元共享一条长边的单元式一个连通单元,是湖泊的一部分。
Input:
有多组数据。每组的第1行有3个整数N,M和K。第2行到第K+1行,是整数R和C,表示被淹没的位置。
Ouput:
对每组测试数据,输出有最大湖泊的单元的数目。
Sample Input:
3 4 5
3 2
2 2
3 1
2 3
1 1
Sample Output:
4
Codeing:
import java.util.Scanner;
public class Main {
static int n = 0; //row
static int m = 0; //column
static int k = 0;
static int recentCount = 0;
static int bestCount = 0;
static int[][] flag ;
static void search(int x, int y){
if(x < 1|| x > n-2|| y < 1|| y > m-2){
return;
}
if(flag[x][y-1] == 1){
recentCount++;
flag[x][y-1] = 0;
search(x,y-1);
}
if(flag[x][y+1] == 1){
recentCount++;
flag[x][y+1] = 0;
search(x,y+1);
}
if(flag[x-1][y] == 1){
recentCount++;
flag[x-1][y] = 0;
search(x-1,y);
}
if(flag[x+1][y] == 1){
recentCount++;
flag[x+1][y] = 0;
search(x+1,y);
}
}
public static void main(String[] args) {
while (true){
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt() + 2;
m = scanner.nextInt() + 2;
k = scanner.nextInt();
flag = new int[101][101];
for(int i = 0; i < k; i++){
int a = scanner.nextInt();
int b = scanner.nextInt();
flag[a][b] = 1;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(flag[i][j] == 1){
flag[i][j] = 0;
search(i,j);
if(recentCount > bestCount){
bestCount = recentCount;
recentCount = 0;
}
}
}
}
System.out.println(bestCount+1);
bestCount = 0;
}
}
}
习题B:骑士移动
Description:
你的一个朋友正在研究骑士旅行问题(TKP)。在一个有n个放个的棋盘上,你得找到一条最短的封闭骑士旅行的路径,使能够遍历每个方格一次。他认为问题的最困难部分在于,对两个给定的方格,确定骑士移动所需的最小步数。你曾经解决过这类问题,找到这个路径应该不困难。
当然,你知道反之亦然,所以你帮助他编写一个程序,解决这个“困难的”部分。
你的任务是:输入有两个方格a和b,确定骑士在最短路径上从a到b移动的次数。
Input:
输入包含一组或多组测试例。每个测试例一行,是两个方格,用空格隔开。棋盘上的一个方格用一个字符串表示,字母(a-h)表示列,数字(1-8)表示行。
Ouput:
对每个测试例,输出一行:“To get from xx to yy takes n knight moves.”。
Sample Input:
e2 e4
a1 b2
b2 c3
a1 h8
a1 h7
h8 a1
b1 c3
f6 f6
Sample Output:
To get from e2 to e4 takes 2 knight moves.
To get from a1 to b2 takes 4 knight moves.
To get from b2 to c3 takes 2 knight moves.
To get from a1 to h8 takes 6 knight moves.
To get from a1 to h7 takes 5 knight moves.
To get from h8 to a1 takes 6 knight moves.
To get from b1 to c3 takes 1 knight moves.
To get from f6 to f6 takes 0 knight moves.
Codeing:
import java.util.*;
class Point {
int x;
int y;
int sum;
}
public class Main{
static int[][] qq = new int[8][8];
public static void main(String[] args) {
Scanner s = new Scanner(System.in
);
String[][] ss = new String[8][2];
for (int i = 0; i < ss.length; i++) {
for (int j = 0; j < ss[i].length; j++) {
ss[i][j] = s.next();
}
}
int count = 0;
for (int i = 0; i < ss.length; i++) {
qq = new int[8][8];
int ax = ss[i][0].charAt(1) - '1';
int ay = ss[i][0].charAt(0) - 'a';
int bx = ss[i][1].charAt(1) - '1';
int by = ss[i][1].charAt(0) - 'a';
count = dfs(ax, ay, bx, by);
System.out.println("To get from " + ss[i][0] + " to " + ss[i][1] + " takes " + count + " knight moves.");
}
}
public static int dfs(int x, int y, int bx, int by) {
Queue<Point> queue = new LinkedList<Point>();
int xd[] = { -2, -2, -1, -1, 1, 2, 1, 2 };
int yd[] = { -1, 1, -2, 2, -2, -1, 2, 1 };
Point p = new Point();
p.x = x;
p.y = y;
p.sum = 0;
queue.offer(p);
qq[p.x][p.y] = 1;
while (!queue.isEmpty()) {
p = queue.poll();
if (p.x == bx && p.y == by) {
break;
}
for (int i = 0; i < 8; ++i) {
Point p1 = new Point();
p1.x = p.x + xd[i];
p1.y = p.y + yd[i];
p1.sum = p.sum + 1;
if (p1.x >= 0 && p1.y >= 0 && p1.x <= 7 && p1.y <= 7 && qq[p1.x][p1.y] == 0) {
queue.offer(p1);
qq[p1.x][p1.y] = 1;
}
}
}
return p.sum;
}
}