前言
实习终于快结束了,今天有空顺便带来蓝桥杯算法训练的算法题的思路与题解,后续有空再继续出题解哈。
ALGO1000-kAc给糖果你吃
资源限制
内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
kAc有n堆糖果,每堆有A[i]个。
kAc说你只能拿m次糖果,聪明的你当然想要拿最多的糖果来吃啦啦啦~
//第二天,kAc问你还想吃糖果么?(嘿嘿嘿)说着眼角路出奇怪的微笑...
输入格式
第一行两个数字n和m,第二行有n个数字A[i]。
输出格式
输出一行表示最多能拿几个糖果。
样例输入
2 2
1 2
样例输出
3
数据规模和约定
0<n≤1000
其余数字都是不超过1,000,000,000的非负整数。
题解
第一道题是很简单的贪心,拿的时候就拿n堆中前m大的糖果堆即可。使用个排序,将前m个从大到小的加上来就好了。
代码
package 算法训练;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Scanner;
public class ALGO_1000_kAc给糖果你吃 {
public static void main(String[] args) throws Exception {
// TODO 自动生成的方法存根
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String p = br.readLine();
String a[] = p.split(" ");
int n = Integer.parseInt(a[0]);
int m = Integer.parseInt(a[1]);
long mp[] = new long[n];
p = br.readLine();
a = p.split(" ");
for(int i = 0;i<n;i++) {
mp[i] = Long.parseLong(a[i]);
}
int ans = 0;
Arrays.sort(mp);
for(int i = n - 1;i >= n-m;i--) {
ans += mp[i];
}
System.out.println(ans);
}
}
ALGO1001-跳马
资源限制
内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
一个8×8的棋盘上有一个马初始位置为(a,b),他想跳到(c,d),问是否可以?如果可以,最少要跳几步?
输入格式
一行四个数字a,b,c,d。
输出格式
如果跳不到,输出-1;否则输出最少跳到的步数。
样例输入
1 1 2 3
样例输出
1
数据规模和约定
0<a,b,c,d≤8且都是整数。
题解
第二道题是一道bfs广度优先搜索:BFS 是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。一般用队列数据结构来辅助实现 BFS 算法。
BFS广度优先搜索详解
直接上图,在BFS算法,我们一般先设置一个队列Queue Q
将A放入队列Q中,此时Q中有{ A }
接着在循环中,取出队头的元素,也就是A ,发现A连接着B、E、D,我们以此将它们放入Q中,此时Q中有{B,E,D}
接着在循环中,取出队头的元素,也就是B,发现B连接着C,我们将它放入Q中,此时Q中有{E,D,C}
接着在循环中,取出队头的元素,也就是E,发现E连接着F,G,我们将它们放入Q中,此时Q中有{D,C,F,G}
........
最后就遍历完了整个图,我们只需要在循环中加入对应题目的条件判断即可
题解
在这个题目中,首先我们要先知道象棋中,马是怎么跳的:
//也就是说,马如果初始位置在{0,0},那么它可以跳向{-1,2},{2,-1},{1,2},{2,1},{1,-2},{-2,1},{-1,-2},{-2,-1}
//所以,我们可以设置一个二维数组来表示马的去向
public static int xy[][] = {{-1,2},{2,-1},{1,2},{2,1},{1,-2},{-2,1},{-1,-2},{-2,-1}};
接着按照BFS的代码,将出发点{a,b}还有当前中的步数time放入队列Q中,然后每次取出队列中队头的元素,判断位置是不是{c,d},如果是那么直接输出步数time,直接上最终代码。
package 算法训练;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class ALGO_1001_跳马 {
public static int a,b,c,d;
public static int xy[][] = {{-1,2},{2,-1},{1,2},{2,1},{1,-2},{-2,1},{-1,-2},{-2,-1}};
public static boolean is[][];
public static boolean check(int x,int y) {
if(x > 0 && y > 0 && x <= 8 && y <= 8 && !is[x][y]) {
return true;
}
return false;
}
public static class stu{
int x;
int y;
int time;
public stu(int x,int y,int time) {
this.x = x;
this.y = y;
this.time = time;
}
@Override
public int hashCode() { //重写hashCode 方法
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) { //重写equals 方法
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
stu other = (stu) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner cin = new Scanner(System.in);
a = cin.nextInt();
b = cin.nextInt();
c = cin.nextInt();
d = cin.nextInt();
is = new boolean[11][11];
stu finalPoint = new stu(c,d,0);
Queue<stu> Q = new LinkedList<stu>();
Q.add(new stu(a,b,0));//把初始点放进去
int ans = -1;
while(!Q.isEmpty()) {
stu nowPoint = Q.poll();
int x = nowPoint.x;
int y = nowPoint.y;
System.out.println("x:"+x+"-->y:"+y);
int time = nowPoint.time;
if(nowPoint.equals(finalPoint)) {
ans = time;
break;
}
for(int i = 0;i<8;i++) {
int nx = x + xy[i][0];
int ny = y + xy[i][1];
if(check(nx,ny)) {
//可以放进入
Q.add(new stu(nx,ny,time+1));
is[nx][ny] = true;
}
}
}
System.out.println(ans);
}
}
ALGO1003-礼物
资源限制
内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
JiaoShou在爱琳大陆的旅行完毕,即将回家,为了纪念这次旅行,他决定带回一些礼物给好朋友。
在走出了怪物森林以后,JiaoShou看到了排成一排的N个石子。
这些石子很漂亮,JiaoShou决定以此为礼物。
但是这N个石子被施加了一种特殊的魔法。
如果要取走石子,必须按照以下的规则去取。
每次必须取连续的2*K个石子,并且满足前K个石子的重量和小于等于S,后K个石子的重量和小于等于S。
由于时间紧迫,Jiaoshou只能取一次。
现在JiaoShou找到了聪明的你,问他最多可以带走多少个石子。
输入格式
第一行两个整数N、S。
第二行N个整数,用空格隔开,表示每个石子的重量。
输出格式
第一行输出一个数表示JiaoShou最多能取走多少个石子。
样列输入
8 3
1 1 1 1 1 1 1 1
样列输出
6
样列解释
任意选择连续的6个1即可。
数据规模和约定
对于20%的数据:N<=1000
对于70%的数据:N<=100,000
对于100%的数据:N<=1000,000,S<=10^12,每个石子的重量小于等于10^9,且非负
题解
这道题我们可以使用二分查找加上前缀和来解题,设置left = 1,right = n,每次查找mid值,判断这个值是否符合条件:前K个石子的重量和小于等于S,后K个石子的重量和小于等于S,如果符合就让left = mid+1;否则right = mid;具体细节见代码:(还有一点要说的是,如果这个题使用的是Java,我们需要用BufferedReader来输入,使用Scanner的话会爆内存,很坑)
代码
package 算法训练;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;
public class ALGO_1003_礼物 {
public static int n;
public static long status;
public static long sum[] = new long[1000010];
public static boolean check(int pi) {
for(int i = pi;i<=n-pi;i++) {
if(sum[i] - sum[i-pi] <= status && sum[i+pi] - sum[i] <= status) {
return true;
}
}
return false;
}
public static void main(String[] args) throws Exception {
// TODO 自动生成的方法存根
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String p = br.readLine();
String a[] = p.split(" ");
n = Integer.parseInt(a[0]);
status = Long.parseLong(a[1]);
p = br.readLine();
a = p.split(" ");
for(int i = 1;i<=n;i++) {
sum[i] = Long.parseLong(a[i-1]);
sum[i] += sum[i-1];
}
int left = 1;
int right = n;
while(left < right) {
int mid = (left + right)/2;
if(check(mid)) {
left = mid+1;
}
else {
right = mid;
}
}
System.out.println(2*(left-1));
}
}