本小白为了提高自己的算法能力,今年参加了许多算法比赛锻炼自己。其中蓝桥省二、睿抗省三、百度之星铁奖。虽然不像许多大佬能在几个月内拿上好几个国奖,但是对于我自身来说参加比赛能锻炼自己、提高自己就已经足够了。
睿抗结束后,本来以为近期没什么比赛了。忽然间发现这个杂交水稻杯,虽然说是第七届大赛,但是在网上几乎找不到往届比赛的资料。第一感觉就是一个水赛,但是别说获奖证书上袁隆平的签名又显得像模像样,报名费50,ACM赛制,跟其他比赛相比还是比较便宜的,就果断报名了。比赛中写出了A-E题,因此接下来我将以我的视角来解析这几道题,因为能力有限,只能浅谈自己的认知。(所有代码均为java)
A 回文素数
这个题无外乎就是把每个数进行素数判断和回文判断,都符合就输出。
public static boolean huiwen(long a) {
boolean b = false;
long temp = a;
long sum = 0;
while(a > 0) {
sum = sum * 10 + (a % 10);
a /= 10;
}
if(sum == temp)
b = true;
return b;
}
public static boolean sushu(long a) {
boolean b = true;
if(a == 1)
b = false;
for(int i = 2;i < a;i++) {
if(a % i == 0) {
b = false;
break;
}
}
return b;
}
难点在于在不超时的情况下,把所有符合条件的数输出。通过测试发现,当n = 4,6,8时,符合条件的数均为0个(不知道为什么ㄒoㄒ)。n = 7,9时,运行超时了,由于掌握的方法不多,没法优化代码,只能另辟蹊径。因此我打算直接输出结果,反正n只有9个数,把每种情况列出来不就行么。前面几个还好,就是这最后一个n = 9。因为题目要求用空格间隔,因此我将每个符合条件的数进行输出的同时输出一个“ ”。等到输出完成后(跑了两个半小时。。),因为还要输出个数,先把输出结果全部复制粘贴到一个String变量中,然后用split的方法,把空格删除放进一个数组中,再读取数组的length就大功告成了~~~
B 小酬宾
这题乍一看我还以为是一道贪心算法的题目,结果没想到只需要排个序,将最高单价打个折就行。
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
double x = input.nextDouble();
int[] product = new int[n];
for(int i = 0;i < n;i++) {
product[i] = input.nextInt();
}
Arrays.sort(product);
double sum = 0;
for(int j = 0;j < n;j++) {
if(j != n - 1)
sum += product[j];
else
sum += product[j] * (x / 10);
}
System.out.printf("%.2f", sum);
}
}
C 班级聚会
这道题我认为应该是涉及图论的知识,但是我对数据结构的算法并不是很熟悉,这里就没有用。我的方法是,定义一个二位数组存储每个城市的人数和距莫斯科的距离,定义一个一维数组存储城市的名字。然后再定义一个数组,分别存储每个城市到这个城市的花费总和。谁的花费越少,就记录下这个下标,然后按下标输出最小花销和城市名。但是我这里还是有缺陷的,按道理说,如果输入的时候,不是从远到近将每个城市的信息进行输入的,那就还需要进行排序。这里我看输入样例是从远到近就试了一下不需要排序的输入策略,没想到通过了,但是应该还是不够严谨的。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
boolean b =true;
int[][] S = new int[150][2];
String[]city = new String[150];
int count = 0;
while(b) {
S[count][0] = input.nextInt();
S[count][1] = input.nextInt();
city[count] = input.next();
count ++;
if(city[count - 1].equals("Moscow"))
b = false;
}
int[][] SS = new int[count][2];
for(int i = count - 1;i >= 0;i--) {
SS[i][0] = S[i][0];
SS[i][1] = S[i][1];
}
long[] sum = new long[count];
long minSum = 0;
int minsign = 0;
for(int j = 0;j < count;j++) {
for(int k = 0;k < count;k++) {
sum[j] += Math.abs(S[j][1] - S[k][1]) * S[k][0];
}
if(j == 0)
minSum = sum[j];
else {
if(sum[j] < minSum) {
minSum = sum[j];
minsign = j;
}
}
}
System.out.print(city[minsign] + " " + minSum);
}
}
D 乱头发日
这道题就是读起来不太好懂,其实做法不难。最先输入的在最后面,最后输入的在最前面。高的牛可以看到他前面所有比它矮的牛,但是一旦遇到比它高的牛,在这头牛之后即使仍然有矮牛也看不见。最后将所有能看见的牛的数量进行求和就行。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int[] niu = new int[n];
for(int i = 0;i < n;i++) {
niu[i] = input.nextInt();
}
int count = 0;
for(int j = 0;j < n - 1;j++) {
for(int k = j + 1;k < n;k++) {
if(niu[j] > niu[k])
count++;
else
break;
}
}
System.out.print(count);
}
}
E 吃棋子
这道题也是一道需要去理解题意的题目,研究题意可以发现一些规律。在纵轴方向上,两个棋子的坐标之差如果为奇数,那么只可能是Alice赢棋。如果坐标只差为偶数,只可能是Bob赢棋。那么其他情况下,比如Bob起始位置就和Alice同行或在其之上,两个人就无法分出胜负。在一般情况下,只能是XX赢棋,那么只会出现两种情况,XX赢,或者两个人无法分出胜负。那么要怎样确认能不能赢棋,我一开始傻傻地在棋盘上模拟他们可能走的情况,但是根本就模拟不出来,因为题目要求走法是最优解。能赢棋的一方肯定想每一步都把对方的走位限制死最后就能吃棋,不能赢棋的一方肯定想尽量远离对方,使得在有限的纵向位移中,横向位移追不上自己,使得最后两个人无法分出胜负。
模拟每个人可以走的位置,Alice是向下,向左下,向右下。Bob是向上,向左上,向右上。在两个棋子相遇的那一行中,如果不能赢的一方,有任意一条线不被赢的一方所包住,那么最终就是两个人无法分出胜负。如果所有线都被包住,那么就是能赢的一方赢了。这里的线也可以理解成小时候玩的涂色游戏,经过的格子被涂上相应的颜色。如果相遇的那一行中,有任意一个格子的颜色与这一行其他格子的颜色不同,则两个人无法分出胜负。
将能够位移的距离依次相减和相加在起始横坐标上,在横轴上会取得一段距离,只要能赢的一方能包住对方的距离就能获胜。需要注意的是,棋盘是有边界的,不能赢的一方在越过边界时需要和起始位置距边界的距离进行取大或取小操作。而能赢的一方不需要,因为能赢的一方只要保证在棋盘内能包住对方即可。而不能赢的一方越过边界可能会导致对方无法包住的情况,所以需要进行判断。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int t = input.nextInt();
for(int i = 0;i < t;i++) {
int h = input.nextInt();
int w = input.nextInt();
int xa = input.nextInt();
int ya = input.nextInt();
int xb = input.nextInt();
int yb = input.nextInt();
int xcha = xb - xa;
int ycha = Math.abs(ya - yb);
if(xcha <= 0) {
System.out.println("Draw");
continue;
}
if(xcha % 2 == 0) {
int leftYa = ya - xcha / 2;
int leftYb = yb - xcha / 2;
int rightYa = ya + xcha / 2;
int rightYb = yb + xcha / 2;
if(Math.max(leftYa, 1) >= leftYb && Math.min(w, rightYa) <= rightYb)
System.out.println("Bob");
else
System.out.println("Draw");
}else {
int leftYa = ya - xcha / 2 - 1;
int leftYb = yb - xcha / 2;
int rightYa = ya + xcha / 2 + 1;
int rightYb = yb + xcha / 2;
if(Math.max(leftYb, 1) >= leftYa && Math.min(w, rightYb) <= rightYa)
System.out.println("Alice");
else
System.out.println("Draw");
}
}
}
}