哈喽呀!!!各位伙伴们大家好,今天给大家带来蓝桥杯的题目--日期统计。接下来我会用两种方法--dfs和--暴力。供各位小伙伴们来参考学习。
问题描述
小蓝现在有一个长度为 100 的数组,数组中的每个元素的值都在 0 到 9 的范围之内。数组中的元素从左至右如下所示:
5 6 8 6 9 1 6 1 2 4 9 1 9 8 2 3 6 4 7 7 5 9 5 0 3 8 7 5 8 1 5 8 6 1 8 3 0 3 7 9 2 7 0 5 8 8 5 7 0 9 9 1 9 4 4 6 8 6 3 3 8 5 1 6 3 4 6 7 0 7 8 2 7 6 8 9 5 6 5 6 1 4 0 1 0 0 9 4 8 0 9 1 2 8 5 0 2 5 3 3
现在他想要从这个数组中寻找一些满足以下条件的子序列:
子序列的长度为 8;
这个子序列可以按照下标顺序组成一个 yyyymmdd 格式的日期,并且要求这个日期是 2023 年中的某一天的日期,例如 20230902,20231223。yyyy 表示年份,mm 表示月份,dd 表示天数,当月份或者天数的长度只有一位时需要一个前导零补充。
请你帮小蓝计算下按上述条件一共能找到多少个不同 的 2023 年的日期。对于相同的日期你只需要统计一次即可。
通过dfs递归来查找满足条件的日期要求。日期的前4位为2023,这个是不变的。重要的是后4位。对于1,3,5,7,8,10,12这几个月份有31天,对于2月有28天,对于其他月份有30天。查找的日期要满足以上的要求。还应该要注意的是满足的日期不能重复。
具体代码如下:
#include<bits/stdc++.h>
using namespace std;
int a[100],ans;
bool b[20240000];//用来判断是否重复
bool cheak(int data) {//检测日期是否满足
if(b[data]) return false;
int mm=data/100%100;
int dd=data%100;
if(mm<1||mm>12) return false;
if(mm==1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12) {
if(dd<1||dd>31) return false;
} else if(mm==2) {
if(dd<1||dd>28) return false;
} else {
if(dd<1||dd>30) return false;
}
b[data]=1;
return true;
}
void dfs(int x,int pos,int data) { //x是到数组第几个,pos是有几个数据了,data是数据。
if(x==100) return;
if(pos==8) {
if(cheak(data)) ans++;
return;
}
if((pos==0&&a[x]==2)||
(pos==1&&a[x]==0)||
(pos==2&&a[x]==2)||
(pos==3&&a[x]==3)||
(pos==4&&a[x]>=0&&a[x]<=1)||
(pos==5&&a[x]>=0&&a[x]<=9)||
(pos==6&&a[x]>=0&&a[x]<=3)||
(pos==7&&a[x]>=0&&a[x]<=9)) {
dfs(x+1,pos+1,data*10+a[x]);
}
dfs(x+1,pos,data);
}
int main() {
ios::sync_with_stdio(0);//用于调整C++的输入输出流与C标准库的输入输出流的同步方式。
cin.tie(0);//用于解除标准输入流 `cin` 和标准输出流 `cout` 之间的绑定关系。
for(int i=0; i<100; i++) {
cin>>a[i];
}
dfs(0,0,0);//初始化
cout<<ans;
}
暴力解决思路:总共8位,一位一位的确定,通过Set方法去重。
具体代码如下:
#include <iostream>
#include <set>
using namespace std;
int main() {
int arr[100] = { 5,6,8,6,9,1,6,1,2,4,9,1,9,8,2,3,6,4,7,7,5,9,5,0,3,8,7,5,8,1,5,8,6,1,8,3,0,3,7,9,2,
7,0,5,8,8,5,7,0,9,9,1,9,4,4,6,8,6,3,3,8,5,1,6,3,4,6,7,0,7,8,2,7,6,8,9,5,6,5,6,1,4,0,1,
0,0,9,4,8,0,9,1,2,8,5,0,2,5,3,3
};
int month[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
int monthChecke[12] = { 0 };//记录月份访问状态防止重复遍历
set<int> uniqueSet;//利用set去重
for (int i = 0; i < 93; i++) { //年份的第一位只用遍历到倒数第8位即可
if (arr[i] == 2) {
for (int j = i + 1; j < 94; j++ ) { //年份的第一位只用遍历到倒数第7位即可
if (arr[j] ==0) {
for (int k = j + 1; k < 95; k++) {
if (arr[k] == 2) {
for (int l = k + 1; l < 96; l++) {
if (arr[l] == 3) {
for (int a = l+1; a < 97; a++) { //年份的第一位只用遍历到倒数第4位即可
if (arr[a] <2) {// 月份的第一位不能大于2
for (int b = a+1; b < 98; b++) { //月份的第二位
int month1 = arr[a] * 10 + arr[b];
if (0< month1 && month1 <13 && monthChecke[month1-1]==0) { //检查月份是否合法
//记录月份访问状态防止重复遍历
monthChecke[month1-1] = 1;
for (int c = b + 1; c < 99; c++) { //日期的第一位只用遍历到倒数第2位即可
if (arr[c] < 4) {
//日期的第一位不能大于3,可以取0,1,2,3
for (int d = c + 1; d < 100; d++) { //日期的第二位
int day1 = arr[c] * 10 + arr[d];
if (0 < day1 && day1 <= month[month1 - 1]) { //检查日期是否合法
//将得到的日期转化为四位数存入set中去重,年份都是2023,因此不用特殊处理
uniqueSet.insert(arr[a] * 1000 + arr[b] * 100 + arr[c] * 10 + arr[d]);
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
cout << uniqueSet.size() << endl;
return 0;
}
代码执行结果如下:
好啦!!以上就是本篇博客的全部内容。喜欢的记得点赞+关注+收藏。后期小编还会继续更新关于蓝桥杯的内容。祝大家每天学习进步,天天开心。😃😀😀