历年来的蓝桥杯所刷的题目。
2013年蓝桥杯
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 //
// Created by ZhiNian on 2019/3/25.
//
/*
题目标题: 高斯日记
大数学家高斯有个好习惯:无论如何都要记日记。
他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210
后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?
高斯出生于:1777年4月30日。
在高斯发现的一个重要定理的日记上标注着:5343,因此可算出那天是:1791年12月15日。
高斯获得博士学位的那天日记上标着:8113
请你算出高斯获得博士学位的年月日。
提交答案的格式是:yyyy-mm-dd, 例如:1980-03-21
请严格按照格式,通过浏览器提交答案。
注意:只提交这个日期,不要写其它附加内容,比如:说明性的文字。
答案是:1799-07-16
*/
using namespace std;
const int N = 8113;
int main() {
int year = 1777;
int mouth = 4;
int day = 30;
for (int i = 1; i < N; ++i) {
day++;
if (((year % 4) == 0 && (year % 100 != 0)) || (year % 400 == 0)) {
if (day == 30 && mouth == 2) {
day = 1;
mouth++;
}
if (day == 31 && (mouth == 4 || mouth == 6 || mouth == 9 || mouth == 11) ){//当日期为30+1时 并且为2/4/6/9/11月时 加 1 月
day = 1;
mouth++;
}
if (day == 32 && (mouth == 1 || mouth == 3 || mouth == 5 || mouth == 7 || mouth == 8 || mouth == 10)) {
day = 1;
mouth++;
}
if (day == 32 && mouth == 12) {
year++;
day = 1;
mouth = 1;
}
} else {
if (day == 29 && mouth == 2) {
day = 1;
mouth++;
}
if (day == 31 && (mouth == 4 || mouth == 6 || mouth == 9 || mouth == 11) ){//当日期为30+1时 并且为2/4/6/9/11月时 加 1 月
day = 1;
mouth++;
}
if (day == 32 && (mouth == 1 || mouth == 3 || mouth == 5 || mouth == 7 || mouth == 8 || mouth == 10)) {
day = 1;
mouth++;
}
if (day == 32 && mouth == 12) {
year++;
day = 1;
mouth = 1;
}
}
}
cout << year << " " << mouth << " " << day << endl;
return 0;
}
此题还是很简单的,记住闰年判断条件就好,然后用5343去验证程序,再进行8113的结果运算。
1 | // |
这一题不难,但是需要积累一些C++知识,比如当find
函数找不到时会返回一个string::npos
,并且用stringstream
去转换int
型和string
型的函数,这些需要好好地记下来,很多地方都可以用!
1 | // |
简单递归,没花多少时间,就不去说什么了,注释都很清楚,但是今天做了一个难的递归,整数划分,见我的另一篇博客。
1 | // |
作为一个积极写注释的人,好像不需要什么过多的语言描述算法了,这个题目让我学会了一点点vector的用法还有stirng.find(char x)和string::npos的返回值,总得来说还是思路清晰很顺利,就是编程是个问题,慢慢积累吧,加油!
第五题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63//
// Created by ZhiNian on 2019/7/16.
//
/*
题目标题:前缀判断
如下的代码判断 needle_start指向的串是否为haystack_start指向的串的前缀,如不是,则返回NULL。
比如:"abcd1234" 就包含了 "abc" 为前缀
char* prefix(char* haystack_start, char* needle_start)
{
char* haystack = haystack_start;
char* needle = needle_start;
while(*haystack && *needle){
if(______________________________) return NULL; //填空位置
}
if(*needle) return NULL;
return haystack_start;
}
请分析代码逻辑,并推测划线处的代码,通过网页提交。
注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!
*/
using namespace std;
/**
*
* @param haystack_start 母串
* @param needle_start 前缀
* @return
*/
char *prefix(char *haystack_start, char *needle_start) {
char *haystack = haystack_start;
char *needle = needle_start;//前缀
while (*haystack && *needle) {//两个指针都没有越界
// if(______________________________) return NULL; //填空位置
//移动指针
//并判断
if (*(haystack++) != *(needle++))return NULL;
}
if (*needle) return NULL;
return haystack_start;
}
int main(int argc, const char *argv[]) {
cout << prefix("abcd123", "abd") << endl;
return 0;
}
这一题,我刚刚开始最不能理解的,就是这一行代码
1 | while (*haystack && *needle) |
但是后面知道了,这代表的就是两个指针都没有越界的时候,就是指向的都还是字符串的时候,那么就进行循环,这是一个前缀判断,如果跳出这个循环,说明字串已经循环完毕,然后如果发现字串没循环完毕,而母串循环完毕了,就直接输出null,说明了在循环内是要判断,字串和母串是否依次相同,如果不同就跳出return null,所以,在空里需要满足的功能是,依次往下搜寻,并且进行判断是否不同,所以可以把++放后面,这样进行的就是,先用了再递归,然后这一题就迎刃而解了。
对于代码填空题,有一个很好的方法,就是首先把代码复制进编译器,把所需要填的空首先先注释掉,看看编译能否通过,如果编译都没有通过,就可以通过编译未通过的提示进行填写。
1 | // |
在这一题中,通过调试,通过编译,也没有找到到底是如何填这个空,到最后还是通过一点点的肉眼观察去尝试,然后发现
1 | if (x[0] == '+') ev.result = v1.result + v2.result; |
这一串代码就是说将v1和v2运算,所以我猜测,填的空是
1 | evaluate(x + 1 + 1); |
但是还有一个技巧就是,程序不会白白去留下别的不用的数字,就像物理考试,不可能多给你一个物理量,肯定都是有用的,所以答案应该是
1 | evaluate(x + 1 + v1.n); |
然后理解起来就是,前一个v1吃掉了前一部分的值,然后v2当然要吃掉剩下的值,然后将两个值进行运算得到最终的结果。
第七题
1 | // |
这一道题,难点在于,怎么样拆分输入的数据,这个很重要,学会了用while(getline())进行拆分,学会了怎么样字符串转数字的简单函数,怎么样通过sort函数排序。主要是这三点吧。否则换别的方法,拆分就很难了,排序还得自己写,转数字肯定就也是自己写的一个很复杂的函数,时间也浪费了很多。
第八题
1 | // |
这一题不难,就是用的是枚举的思想,然后反向扫描找到最大的那一个,但是在老师的教导中,又学会了一个知识点,就是set的运用,set就像是一个集合,它中的元素不允许重复,可以使用set去存入有些可能重复但是重复却没有用的数据从而提高效率。
当然这个题目还有另一种解法:
1 |
|
就是这么的简单,但是这就是数学基础的问题了,需要熟悉不定方程。
2014年蓝桥杯
第一题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34//
// Created by ZhiNian on 2019/3/31.
//
/*
标题:猜年龄
小明带两个妹妹参加元宵灯会。别人问她们多大了,她们调皮地说:“我们俩的年龄之积是年龄之和的6倍”。
小明又补充说:“她们可不是双胞胎,年龄差肯定也不超过8岁啊。”
请你写出:小明的较小的妹妹的年龄。
注意: 只写一个人的年龄数字,请通过浏览器提交答案。不要书写任何多余的内容。
*/
using namespace std;
int main() {
for (int i = 1; i < 100; ++i) {
for (int j = 1; j < 100; ++j) {
if ((i * j) == (6 * (i + j)) && (abs(i - j) <= 8) && (i != j))
/* 1:(i * j) == (6 * (i + j)):我们俩的年龄之积是年龄之和的6倍
* 2:abs(i - j) <= 8: 年龄差肯定也不超过8岁啊
* 3:(i != j):她们可不是双胞胎
*/
cout << i << " " << j << endl;
}
}
return 0;
}解析注释有了,很简单。
第二题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33//
// Created by ZhiNian on 2019/3/31.
//
/*
标题:切面条
一根高筋拉面,中间切一刀,可以得到2根面条。
如果先对折1次,中间切一刀,可以得到3根面条。
如果连续对折2次,中间切一刀,可以得到5根面条。
那么,连续对折10次,中间切一刀,会得到多少面条呢?
答案是个整数,请通过浏览器提交答案。不要填写任何多余的内容。
*/
/*
* 通过撕纸条发现,对折3次是 9根
* 找规律很明显可知是 2^n+1
* 所以10次是 2^10+1=2015
*/
/*
* 还可以这么想:
* 不对折,切一刀就是一刀
* 对折切一刀,就是切两刀
* 再对折去切一刀,等于再之前的基础上砍得两倍的刀
* 就比如上一次砍n刀,对折后砍n刀等于砍了2n刀
* 而一根面条砍n刀就会产生n+1条面条
* 对折10次砍一刀相当于不对折 砍2^10刀 = 砍1024刀 相当于 产生了 1025根面条
*/好像没什么可以说的。
第三题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111//
// Created by ZhiNian on 2019/3/31.
//
/*
标题:神奇算式
由4个不同的数字,组成的一个乘法算式,它们的乘积仍然由这4个数字组成。
比如:
210 x 6 = 1260
8 x 473 = 3784
27 x 81 = 2187
都符合要求。
如果满足乘法交换律的算式算作同一种情况,那么,包含上边已列出的3种情况,一共有多少种满足要求的算式。
请填写该数字,通过浏览器提交答案,不要填写多余内容(例如:列出所有算式)。
*/
using namespace std;
int ansans = 0;
bool check1(int num, int ans) {
stringstream ss1, ss2;
string snum;
string sans;
ss1 << num;
ss1 >> snum;
ss2 << ans;
ss2 >> sans;//将结果和数字全部转换成字符串形式并进行判断
if (sans.length() != 4)//防止长度仅为3就进行下一步的判断
return false;
for (int i = 0; i < 4; ++i) {
if (sans.find(snum[i]) == string::npos)//没有找到相同的字符
return false;
}
return true;
}
bool check2(int src, int r) {
// 先转字符串,排序,比较
string src_str, r_str;
stringstream ss;
ss << src;
ss >> src_str;
stringstream ss1;
ss1 << r;
ss1 >> r_str;
sort(r_str.begin(), r_str.end());
sort(src_str.begin(), src_str.end());
if (r_str == src_str) {
return true;
}
return false;
}
int main() {
for (int i = 1; i < 10; ++i) {//第一位数(最高位)所以从1开始
for (int j = 0; j < 10; ++j) {//第二位数
if (i != j)//前两位不相等
for (int k = 0; k < 10; ++k) {//第三位数
if (k != i && k != j)//第三位不与前两位相等
for (int l = 0; l < 10; ++l) {//第四位数
if (l != i && l != j && l != k)//不与前三位相等
{
int num = i * 1000 + j * 100 + k * 10 + l;//ijkl
if (j != 0) {//两个数的首位不能为0,但是i在开头就排除了
int ans1 = i * (j * 100 + k * 10 + l);//ijk*l
if (check1(num, ans1)) {
ansans++;
cout << num << " " << i << "*" << j * 100 + k * 10 + l << "=" << ans1
<< endl;
}
}
if (k != 0) {//两个数的首位不能为0,但是i在开头就排除了
int ans2 = (i * 10 + j) * (k * 10 + l);//ij*jk
if ((i * 10 + j) < (k * 10 + l) &&
check1(num, ans2)) {//两位数防止交换律产生的重复,所以加一条件:第一个数小于第二个数
ansans++;
cout << num << " " << i * 10 + j << "*" << k * 10 + l << "=" << ans2 << endl;
}
}
// if (l != 0) {//两个数的首位不能为0,但是i在开头就排除了
// int ans3 = (i * 100 + j * 10 + k) * l;//i*jkl
// if (check1(num, ans3)) {
// ansans++;
// cout << num << " " << i * 100 + j * 10 + k * 10 << "*" << l << "=" << ans3
// << endl;
// }
// }
//因为在前面就已经通过一位数乘以三位数枚举过了,所以这里的都是重复的 三位数乘以一位数
}
}
}
}
}
cout << ansans << endl;
return 0;
}check是自己写的判断函数,通过循环去判断字符串中是否有另一个字符串中的字符,而老师用了先排序(C++中algorithm库里的)后直接判断字符串是否相等的方法,然后整体就是这么回事,枚举,筛选,如果把下面的注释全部打开,就会重复,因为乘法交换律,会有一样的 所以可以进行优化。现在发现了,stringstream去把int和string互相转换时非常好用的,还有这样一种枚举的方法,其他的在注释中都有了总结和说明,然后这一题,就到这吧。
2015年蓝桥杯
第一题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35//
// Created by ZhiNian on 2019/3/31.
//
/*
方程整数解
方程: a^2 + b^2 + c^2 = 1000
(或参见【图1.jpg】)
这个方程有正整数解吗?有:a,b,c=6,8,30 就是一组解。
你能算出另一组合适的解吗?
请填写该解中最小的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
答案是:10
*/
using namespace std;
int main() {//32^2=1024所以小于30
for (int i = 1; i < 32; ++i) {
for (int j = 1; j < 32; ++j) {
for (int k = 1; k < 32; ++k) {
if (i * i + j * j + k * k == 1000) {
cout << i << "^2 + " << j << "^2 + " << k << "^2 " << "=1000 " << endl;
}
}
}
}
return 0;
}这一题有点坑,因为我想写6的,但是答案是10,因为我没有看见这么一句话“你能算出另一组合适的解吗?”意思是另一组解的最小值,所以一定要仔细看题!!!
第二题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27//
// Created by ZhiNian on 2019/3/31.
//
/*星系炸弹
在X星系的广袤空间中漂浮着许多X星人造“炸弹”,用来作为宇宙中的路标。
每个炸弹都可以设定多少天之后爆炸。
比如:阿尔法炸弹2015年1月1日放置,定时为15天,则它在2015年1月16日爆炸。
有一个贝塔炸弹,2014年11月9日放置,定时为1000天,请你计算它爆炸的准确日期。
请填写该日期,格式为 yyyy-mm-dd 即4位年份2位月份2位日期。比如:2015-02-19
请严格按照格式书写。不能出现其它文字或符号。
答案是:2017-08-05
*/
using namespace std;
int main(int argc, const char *argv[]) {
int i = 21 + 31;
i += 365;//2015年
i += 366;//2016年
i += 31 + 28 + 31 + 30 + 31 + 30 + 31 + 5;//凑
cout << i << endl;
return 0;
}当然这题有更简单的方法,用Excel表格,直接实现加法,因为天数不是很大,在系统时间范围内,所以可以直接用Excel加,见下图:
就是这么简单,但是呢!!!!!输入答案一定要是 2017-08-05,不能是2017-8-5。注意细节!
第三题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61//
// Created by ZhiNian on 2019/3/31.
//
/*
奇妙的数字
小明发现了一个奇妙的数字。它的平方和立方正好把0~9的10个数字每个用且只用了一次。
你能猜出这个数字是多少吗?
请填写该数字,不要填写任何多余的内容。
答案是:69
*/
using namespace std;
string i2s(int a) {
stringstream ss;
string str;
ss << a;
ss >> str;
return str;
}
bool check(int n) {
string str2 = i2s(n * n);
string str3 = i2s(n * n * n);
if (str2.length() + str3.length() != 10)//长度不为10返回错误
return false;
for (int i = 0; i < str2.length(); ++i) {
if (str3.find(str2[i]) != string::npos)//在立方字符串中找到了平方字符串中的字符返回错误
return false;
}
for (int j = 0; j < str2.length(); ++j) {//在平方字符串中本身找到了重复返回错误
if (str2.find(str2[j]) != j)
/*
* 用的是一个find返回位置的技巧,比如2532,当i循环到0时 str[0]="2" str="2532" 此时str.find("str[0]")=0
* 但是当 i循环到3 str[3]="2" 但是 str.find("str[3]")=0 返回的是第一个2的位置,当位置不同说明有重复数字
* 即 str.find(str[i]) != i
*/
return false;
}
for (int k = 0; k < str3.length(); ++k) {//在立方字符串中本身找到了重复返回错误
if (str3.find(str3[k])!= k)//
return false;
}
return true;
}
int main() {
for (int i = 0; i < 2500; ++i) {//因为2500这个数字的立方已经十一位数了
if (check(i))
cout << i << endl;
}
return 0;
}这是自己写的算法,感觉理解挺简单的,但是觉得自己的判断方法(判断重复)有点傻逼,当然接下来还有老师的算法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include <iostream>
#include <string>
#include <sstream>
#include <set>
using namespace std;
void i2s(int num, string &str) {
stringstream ss;
ss << num;
ss >> str;
}
bool check(string s) {
set<char> ss;
for (int i = 0; i < s.length(); ++i) {
ss.insert(s[i]);
}
return s.size()==10&&ss.size()==10;
}
int main(int argc, const char *argv[]) {
for (int i = 1; i < 100000; ++i) {
string s1, s2;
i2s(i * i, s1);
i2s(i * i * i, s2);
if (check(s1 + s2)) {
cout << i << endl;
break;
}
}
return 0;
}第三题的填充
set的各成员函数列表如下:
c++ stl容器set成员函数:
begin()
–返回指向第一个元素的迭代器c++ stl容器set成员函数:
clear()
–清除所有元素c++ stl容器set成员函数:
count()
–返回某个值元素的个数c++ stl容器set成员函数:
empty()
–如果集合为空,返回truec++ stl容器set成员函数:
end()
–返回指向最后一个元素的迭代器c++ stl容器set成员函数:
equal_range()
–返回集合中与给定值相等的上下限的两个迭代器c++ stl容器set成员函数:
erase()
–删除集合中的元素c++ stl容器set成员函数:
find()
–返回一个指向被查找到元素的迭代器c++ stl容器set成员函数:
get_allocator()
–返回集合的分配器c++ stl容器set成员函数:
insert()
–在集合中插入元素c++ stl容器set成员函数:
lower_bound()
–返回指向大于(或等于)某值的第一个元素的迭代器c++ stl容器set成员函数:
key_comp()
–返回一个用于元素间值比较的函数c++ stl容器set成员函数:
max_size()
–返回集合能容纳的元素的最大限值c++ stl容器set成员函数:
rbegin()
–返回指向集合中最后一个元素的反向迭代器c++ stl容器set成员函数:
rend()
–返回指向集合中第一个元素的反向迭代器c++ stl容器set成员函数:
size()
–集合中元素的数目c++ stl容器set成员函数:
swap()
–交换两个集合变量c++ stl容器set成员函数:
upper_bound()
–返回大于某个值元素的迭代器c++ stl容器set成员函数:
value_comp()
–返回一个用于比较元素间的值的函数而上题老师的算法用到了“c++ stl容器set成员函数:
insert()
–在集合中插入元素”set容器是一个集合,所以当往里面加入重复的元素的时候会自动覆盖,而老师是将,平方和立方两个字符串全部加入到同一个集合,然后组成了ss,当ss的长度为10,说明没有重复的,若有重复的元素则set容器的元素肯定是无法到达10的,这个技巧超级棒,研究完五年的蓝桥杯前面几道题,就先去学一学 STL 特别好用!
2016年蓝桥杯
第一题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38//
// Created by ZhiNian on 2019/3/31.
//
/*
网友年龄
某君新认识一网友。
当问及年龄时,他的网友说:
“我的年龄是个2位数,我比儿子大27岁,
如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄”
请你计算:网友的年龄一共有多少种可能情况?
提示:30岁就是其中一种可能哦.
请填写表示可能情况的种数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
*/
using namespace std;
int ans = 0;
int main() {
for (int i = 10; i < 100; ++i) {//父亲的年龄枚举
int j = i - 27;//通过这样求出假定儿子的年龄
if (i > j && (i / 10 + i % 10 * 10) == j) {//如果儿子的年龄小于父亲的年龄切两位数倒过来相等的话
cout << i << " " << j << endl;//输出
ans++;//计数
}
}
cout << ans << endl;//输出具体有多少种情况
return 0;
}很简单,不多裹述。
第二题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32//
// Created by ZhiNian on 2019/4/2.
//
/*
生日蜡烛
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。
现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的?
请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
*/
using namespace std;
int main() {
for (int i = 0; i < 100; ++i) {//开始吹蜡烛的年龄
for (int j = 0; j < 100; ++j) {//今年年龄
if (j > i)
if ((i + j) * (j - i + 1) / 2 == 236)//求和等于236的时候
cout << i << " " << j << endl;
}
}
return 0;
}
第三题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95//
// Created by ZhiNian on 2019/4/2.
//
/*
方格填数
如下的10个格子
+--+--+--+
| | | |
+--+--+--+--+
| | | | |
+--+--+--+--+
| | | |
+--+--+--+
(如果显示有问题,也可以参看【图7-1.jpg】)
填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)
一共有多少种可能的填数方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
*/
using namespace std;
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int ans = 0;
bool check() {
if (
abs(a[0] - a[1]) == 1 ||
abs(a[0] - a[3]) == 1 ||
abs(a[0] - a[4]) == 1 ||
abs(a[0] - a[5]) == 1 ||
abs(a[1] - a[2]) == 1 ||
abs(a[1] - a[4]) == 1 ||
abs(a[1] - a[5]) == 1 ||
abs(a[1] - a[6]) == 1 ||
abs(a[2] - a[5]) == 1 ||
abs(a[2] - a[6]) == 1 ||
abs(a[3] - a[4]) == 1 ||
abs(a[3] - a[7]) == 1 ||
abs(a[3] - a[8]) == 1 ||
abs(a[4] - a[5]) == 1 ||
abs(a[4] - a[7]) == 1 ||
abs(a[4] - a[8]) == 1 ||
abs(a[4] - a[9]) == 1 ||
abs(a[5] - a[6]) == 1 ||
abs(a[5] - a[8]) == 1 ||
abs(a[5] - a[9]) == 1 ||
abs(a[6] - a[9]) == 1 ||
abs(a[7] - a[8]) == 1 ||
abs(a[8] - a[9]) == 1
)
return false;
return true;
}
void f(int x) {//x为第几个方格
if (x == 10)
if (check())
ans++;
for (int i = x; i < 10; ++i) {//非常 重要的一种全排列方式
int temp;
temp = a[x];
a[x] = a[i];
a[i] = temp;
f(x + 1);
temp = a[x];
a[x] = a[i];
a[i] = temp;
}
}
int main() {
f(0);
cout << ans << endl;
return 0;
}
这里很重要,这是一个全排列加筛选的题目,老师讲了三种全排列的方式,但是这一种是我觉得最容易记忆最容易理解的,先赋初值,然后通过第一个与自己本身和后面的所有的数字去交换得到了第一个位置的全排列,接下来再写递归写进去,到第二个位置的排列往后选,因为第一个位置已经定了,当递归出来的时候再把数字换回来,和下一个交换,可能文字有些难理解,但是就大概是这样意思,这个筛选的check也是脑残方法,比较容易理解的,直接将所有不可以的情况列出来就好。
2017年蓝桥杯
第一题
1 | // |
- 学到了有些时候不一定一直用if if if,还可以switch啊,还有学到了一个函数叫 memset 这个东西太好用了,避免了像以前,还得用循环去初始化一个数组,或许是我没有好好听课,还有就是,当输入二维数组麻烦的时候,可以通过定义一个string的一维数组,去充当二维数组使用!