蓝桥杯C++之日期统计(两种方法)

发布时间:2024年01月18日

哈喽呀!!!各位伙伴们大家好,今天给大家带来蓝桥杯的题目--日期统计。接下来我会用两种方法--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

通过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;
}

代码执行结果如下:

好啦!!以上就是本篇博客的全部内容。喜欢的记得点赞+关注+收藏。后期小编还会继续更新关于蓝桥杯的内容。祝大家每天学习进步,天天开心。😃😀😀

文章来源:https://blog.csdn.net/2201_75413622/article/details/135660785
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。