【洛谷】枚举专题-普通枚举 经典题解之铺地毯、回文日期、扫雷
文章目录
- 铺地毯
- 回文日期
- 扫雷
顾名思义,就是把所有情况全都罗列出来,然后找出符合题⽬要求的那⼀个。因此,枚举是⼀种纯暴⼒的算法。
⼀般情况下,枚举策略都是会超时的。此时要先根据题⽬的数据范围来判断暴⼒枚举是否可以通过。
如果不⾏的话,就要⽤后⾯要学的各种算法来进⾏优化(⽐如⼆分,双指针,前缀和与差分等)。
使⽤枚举策略时,重点思考枚举的对象(枚举什么),枚举的顺序(正序还是逆序),以及枚举的⽅式(普通枚举?递归枚举?⼆进制枚举)。
铺地毯
题目描述

题目解析
本题是一道很简单的普通枚举,思路是将输入的数据用4个数组存储起来。本题唯一需要注意的是在查找时从后往前查找,因为题意要求找某一坐标最后一个覆盖该坐标的地毯,从后往前遍历遇到的第一个覆盖该坐标就是最后一个覆盖该坐标的地毯,若遍历结束都没有找到覆盖该坐标的地毯,则输出-1。
(tip:本题提示注意枚举顺序)
代码
#include <iostream>
using namespace std;const int N = 1e4 + 10;
int n;
int a[N], b[N], g[N], k[N];
int x, y;int find()
{// 从后往前枚举for (int i = n; i >= 1; i--){// 判断是否覆盖if (a[i] <= x && b[i] <= y && a[i] + g[i] >= x && b[i] + k[i] >= y){return i;}}return -1;
}int main()
{cin >> n;for (int i = 1; i <= n; i++){cin >> a[i] >> b[i] >> g[i] >> k[i];}cin >> x >> y;cout << find() << endl;return 0;
}
回文日期
题目描述

题目解析
本题主要需要思考用什么来存储日期数据,也就是枚举对象是什么。本题小编介绍一种最优策略,枚举所有合法月日,根据月日拼成对应月日的回文年,比如月日:0229,拼接后的回文年就是9220,那么92200229这八位数字就符合题意,这样判断这8位数字是否在题意规定范围内,若在则计数器count++。
这样大约只有枚举 12 * 30 = 360次,效率最高。
(tips:本题提示注意枚举对象)
代码
#include <iostream>
#include <string>
using namespace std;int days[] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };int main()
{int d1, d2;cin >> d1 >> d2;int count = 0;// 1、枚举所有的合法月日,并把月日拼成回文年份for (int i = 1; i <= 12; i++){for (int j = 1; j <= days[i]; j++){// 根据月日拼成回文年int y = j % 10 * 1000 + j / 10 * 100 + i % 10 * 10 + i / 10;// 把年月日拼成完整的8位数字int num = y * 10000 + i * 100 + j;if (num >= d1 && num <= d2)count++;}}cout << count;return 0;
}
扫雷
题目描述

题目解析
本题也是一道典型枚举,把第一列的所有取值情况枚举出来,没雷为0,有雷为1。
根据题意知道一共有两种合法的摆放情况,并且均由a[1]的取值决定。若a[1]有雷取值为1,递归推导后续a[i]取值,若后续a[i]取值均为0或1则合法,记录摆放方案的count加1,若a[1]有雷取值为0,继续按上述规则推导,若合法则count继续加1,所以count一共有三种取值:0,1,2。
(补充,递推过程有单向性,所以即可以从a[1]开始从前往后推导,也可以从a[n]开始从后往前推导)

代码
#include <iostream>
using namespace std;const int N = 1e6 + 10;int n;
int a[N], b[N]; //第一列, 第二列//a[1]没雷
bool check1()
{a[1] = 0;//需要枚举到n+1,因为需要判断方案是否满足b[n]的取值for (int i = 2; i <= n + 1; i++){a[i] = b[i - 1] - a[i - 1] - a[i - 2];if (a[i] < 0 || a[i] > 1)return false;}// 判断a[n+1]是否为0,若不为0,返回falseif (a[n+1] != 0)return false;return true;
}//a[1]有雷
bool check2()
{a[1] = 1;//需要枚举到n+1,因为需要判断方案是否满足b[n]的取值for (int i = 2; i <= n + 1; i++){a[i] = b[i - 1] - a[i - 1] - a[i - 2];if (a[i] < 0 || a[i] > 1)return false;}// 判断a[n+1]是否为0,若不为0,返回falseif (a[n+1] != 0)return false;return true;
}int main()
{cin >> n;for (int i = 1; i <= n; i++){cin >> b[i];}int ret = 0;ret += check1(); //a[1]没雷ret += check2(); //a[1]有雷cout << ret << endl;return 0;
}
以上就是小编分享的全部内容了,如果觉得不错还请留下免费的赞和收藏
如果有建议欢迎通过评论区或私信留言,感谢您的大力支持。
一键三连好运连连哦~~

