很多题目都是洛谷上有的,可以自己去搜索
【参考:题目列表 - 洛谷 | 计算机科学教育新生态】
在每日一题中,我会给出题目的算法标签以供同学们自学。 每日一题的难度会越来越大,会尝试覆盖尽可能多的算法竞赛高频考点。给出的题目均在vj.openjudge.com可以找到,对应的视频题解可以在往年真题或者基础班课程中看到(收费)。
每日一题
1.3.2 自然数拆分问题
【参考:P2404 自然数的拆分问题 - 洛谷 | 计算机科学教育新生态】
【参考:SaikrVj | 1.3.2 自然数拆分问题】
1月18日
题目标签:深度优先搜索入门
回溯法=DFS
【参考:题解 P2404 【自然数的拆分问题】 - beelake 的博客 - 洛谷博客】
import java.io.*;
import java.util.*;
public class Main {
static int n;
static List<Integer> list = new ArrayList<>();
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter out = new PrintWriter(System.out);
public static void main(String[] args) throws IOException {
String s1 = in.readLine();
n = Integer.parseInt(s1);
dfs(0, 1);
out.flush();
}
// 7=1+1+1+1+1+1+1 所以不需要去重
// 组合问题 无关顺序 这里需要去重
// pre 上一个数
public static void dfs(int sum, int start) {
if (sum > n) return;
if (sum == n) {
out.print(list.get(0));
for (int i = 1; i < list.size() - 1; i++) {
out.print("+" + list.get(i));
}
out.println("+" + list.get(list.size() - 1));
out.flush();
return;
}
// 7 = 1 + 6 所以 i<=n-1
for (int i = start; i <= n-1; i++) {
// 做选择
sum += i;
list.add(i);
dfs(sum, i);// 递归回溯
// 撤销选择
sum -= i;
list.remove(list.size() - 1);
}
}
}
暴力枚举
#include<iostream>
#include<cstdio>
using namespace std;
int n;
int main()
{
cin>>n;
if(n==1)printf("\n");
else if(n==2)printf("1+1\n");
else if(n==3)printf("1+1+1\n1+2\n");
else if(n==4)printf("1+1+1+1\n1+1+2\n1+3\n2+2\n");
else if(n==5)printf("1+1+1+1+1\n1+1+1+2\n1+1+3\n1+2+2\n1+4\n2+3\n");
else if(n==6)printf("1+1+1+1+1+1\n1+1+1+1+2\n1+1+1+3\n1+1+2+2\n1+1+4\n1+2+3\n1+5\n2+2+2\n2+4\n3+3\n");
else if(n==7)printf("1+1+1+1+1+1+1\n1+1+1+1+1+2\n1+1+1+1+3\n1+1+1+2+2\n1+1+1+4\n1+1+2+3\n1+1+5\n1+2+2+2\n1+2+4\n1+3+3\n1+6\n2+2+3\n2+5\n3+4\n");
else printf("1+1+1+1+1+1+1+1\n1+1+1+1+1+1+2\n1+1+1+1+1+3\n1+1+1+1+2+2\n1+1+1+1+4\n1+1+1+2+3\n1+1+1+5\n1+1+2+2+2\n1+1+2+4\n1+1+3+3\n1+1+6\n1+2+2+3\n1+2+5\n1+3+4\n1+7\n2+2+2+2\n2+2+4\n2+3+3\n2+6\n3+5\n4+4\n");
return 0;
}
1.4.3 网线主管
【参考:SaikrVj | 1.4.3 网线主管】
1月20日
题目标签:二分答案。
提示:对于可以使用枚举找出答案的题目,可以思考答案是否具有单调性,对于具有单调性的数据,我们即可使用二分法求解。
你需要编写一个程序,帮助网线主管确定一个最长的网线长度,并且按此长度对库存中的网线进行切割,能够得到指定数量的网线。
求最大值
与 【参考:P2440 木材加工 - 洛谷 | 计算机科学教育新生态】一样的题目
注意把浮点数化为整数再求
import java.io.*;
import java.util.*;
public class Main {
static int n;// 库存中的网线数
static int k;// 需要的网线数量
static List<Integer> list = new ArrayList<>();
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter out = new PrintWriter(System.out);
public static void main(String[] args) throws IOException {
String s1 = in.readLine();
String[] arr1 = s1.split(" ");
n = Integer.parseInt(arr1[0]);
k = Integer.parseInt(arr1[1]);
int[] arr = new int[n];
int low = 1;// cm 最短为1cm
// int high = 10000000; // 100KM -> cm
int high = Integer.MIN_VALUE; // 100KM -> cm 最长为最长的那根
double temp;
for (int i = 0; i < n; i++) {
temp = Double.parseDouble(in.readLine()); // m
arr[i] = (int) (temp * 100); // cm
high = Math.max(high, arr[i]);
}
int mid;
int result = 0;
while (low <= high) {
mid = (low + high) >> 1;
if (check(mid, arr)) {
result = mid;
low = mid + 1;
} else {
high = mid - 1;
}
}
if (result == 0) {
out.println("0.00");
} else{
out.printf("%.2f",result * 1.0 / 100); // (单位:米)。必须精确到厘米,即保留到小数点后两位。
}
out.flush();
}
public static boolean check(int mid, int[] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i] / mid;
}
return sum >= k;
}
}
1.4.7 借教室
【参考:SaikrVj | 1.4.7 借教室】
1月21日
题目标签:二分答案+差分数组
提示:仔细完成前两天的每日一题,掌握二分答案与差分数组,再来挑战今天的题目。
每张订单其实就可以看作是一个区间(操作),左右区间分别为开始时间和结束时间,所以这不就是一个区间操作吗 =》 差分数组
有上下界,序列满足单调性
如果订单号mid不能满足,此时mid为候选答案,如果[0,mid]里面可能有比mid还早的订单不能满足,那么继续向左靠直到找到最先不能满足的那个订单号 =》二分答案
题目:按照订单的先后顺序依次为每份订单分配教室。如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配
如果一个人无法被满足,则他后面的人全都不能被满足;如果一个人可以被满足,则他前面的人都可以被满足。这恰恰吻合了我们二分的性质。
【参考:题解 P1083 【借教室】 - ShawnZhou 的博客 - 洛谷博客】
import java.io.*;
import java.util.*;
public class Main {
static int n;
static int m;
static int[] line;// 第i天可用于租借的教室数量
static long[] need;// 第i天需要租借的教室数量
// static int[] s;
// static int[] t;
// static int[] d;
static long[] change;//差分数组
public static void main(String[] args) throws IOException {
// BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(System.out);
StreamTokenizer sc = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
sc.nextToken();
n = (int) sc.nval;
sc.nextToken();
m = (int) sc.nval;
// String s1 = in.readLine();
// String[] arr1 = s1.split(" ");
// n = Integer.parseInt(arr1[0]);
// m = Integer.parseInt(arr1[1]);
line = new int[n + 1];
need = new long[n + 2];
change = new long[n + 2];
// 天数与订单均用从 1 开始的整数编号 ,所以这里也从下标1开始存储数据
int[] d = new int[m + 1];
int[] s = new int[m + 1];
int[] t = new int[m + 1];
// String s2 = in.readLine();
// String[] arr2 = s2.split(" ");
// for (int i = 0; i < n; i++) {
// line[i + 1] = Integer.parseInt(arr2[i]);
// }
for (int i = 0; i < n; i++) {
sc.nextToken();
line[i + 1] = (int) sc.nval;
}
// String s3;
// String[] arr3;
// for (int i = 0; i < m; i++) {
// s3 = in.readLine().trim();
// arr3 = s3.split(" ");
// d[i + 1] = Integer.parseInt(arr3[0]);
// s[i + 1] = Integer.parseInt(arr3[1]);
// t[i + 1] = Integer.parseInt(arr3[2]);
// }
for (int i = 0; i < m; i++) {
sc.nextToken();
d[i + 1] = (int) sc.nval;
sc.nextToken();
s[i + 1] = (int) sc.nval;
sc.nextToken();
t[i + 1] = (int) sc.nval;
}
//obj 4什么情况是全都可以成立
// 检查前m个订单是否满足
if (check(m, d, s, t)) {
out.println(0);
out.flush();
return;
}
int low = 1;
int high = m; // 最大的订单号
// 二分答案最小值问题
int mid;
int result = 0;
while (low <= high) {
mid = (low + high) >> 1;
if (check(mid, d, s, t)) {
low = mid + 1;
} else {
result = mid;
high = mid - 1;
}
}
out.println(-1);
out.println(result);
out.flush();
}
// need:[1,mid]之间的需要房间总数,即前x个订单,所以每次都要置0
// 判断能不能满足前x个订单
public static boolean check(int x, int[] d, int[] s, int[] t) {
Arrays.fill(need, 0);// 每次都要置0
Arrays.fill(change, 0);// 每次都要置0
// 因为need都为0,所以change初始化也全为0 change[i]=need[i]-need[i-1]
// // 差分数组变化
//obj 1用差分数组对前x个订单操作进行处理
for (int i = 1; i <= x; i++) {
change[s[i]] += d[i]; // 这里题目最大给了10^9 3个10^9相加就越界了,所以要用int
change[t[i] + 1] -= d[i];
}
// 复原序列need
//obj 2抹平差分数组
for (int i = 1; i <= n; i++) {
need[i] = need[i - 1] + change[i];
if (need[i] > line[i]) // 无法满足
return false;
}
// //obj 3 与上面合并到一起
// for (int i = 1; i <= n; i++)
// if (need[i] > line[i]) // 无法满足
// return false;
return true;
}
}
1.6.5 算24 ?
【参考:SaikrVj | 1.6.5 算24】
1月22日
题目标签:搜索+剪枝、模拟
【参考:P1236 算24点 - 洛谷 | 计算机科学教育新生态】
1.6.7 移动玩具 ?
【参考:SaikrVj | 1.6.7 移动玩具】
1月23日
题目标签:宽度优先搜索
【参考:P4289 [HAOI2008]移动玩具 - 洛谷 | 计算机科学教育新生态】
1.6.6 奶酪 ?
【参考:SaikrVj | 1.6.6 奶酪】
1月24日
题目标签:搜索、路径、数学
【参考:P3958 [NOIP2017 提高组] 奶酪 - 洛谷 | 计算机科学教育新生态】
1.8.1 最短路计数 ?
【参考:SaikrVj | 1.8.1 最短路计数】
1月25日
题目标签:最短路问题
【参考:P1144 最短路计数 - 洛谷 | 计算机科学教育新生态】
1.8.2 最优贸易 ?
【参考:SaikrVj | 1.8.2 最优贸易】
【1月26日每日一题】
题目标签:最短路问题 建立反向边
【参考:P1073 [NOIP2009 提高组] 最优贸易 - 洛谷 | 计算机科学教育新生态】
1.8.3 Telephone Lines S ?
【参考:SaikrVj | 1.8.3 Telephone Lines S】
【1月27日每日一题】
题目标签:最短路问题 分层图 分层图最短路