0%

蓝桥杯

历年来的蓝桥杯所刷的题目。

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
*/
#include <iostream>
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
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
//
// Created by ZhiNian on 2019/3/25.
//
/*
题目标题: 排它平方数

小明正看着 203879 这个数字发呆。

原来,203879 * 203879 = 41566646641

这有什么神奇呢?仔细观察,203879 是个6位数,并且它的每个数位上的数字都是不同的,并且它平方后的所有数位上都不出现组成它自身的数字。

具有这样特点的6位数还有一个,请你找出它!

再归纳一下筛选要求:
1. 6位正整数
2. 每个数位上的数字不同
3. 其平方数的每个数位不含原数字的任何组成数位

答案是一个6位的正整数。

请通过浏览器提交答案。
注意:只提交另一6位数,题中已经给出的这个不要提交。
注意:不要书写其它的内容(比如:说明性的文字)。

答案是:639172
*/

#include <sstream>
#include <iostream>
#include <cstring>

using namespace std;

string int2string(long long int a) {//int型转string
stringstream ss;
string str;
ss << a;
ss >> str;
return str;
}

//int string2int(string str) {//string型转int
// stringstream ss;
// int a;
// ss << str;
// ss >> a;
// return a;
//}

bool check1(long long int s) {
string str = int2string(s);
for (int i = 0; i < 6; ++i) {
for (int j = i + 1; j < 6; ++j) {
if (str[i] == str[j])
return true;//找到相同的
}

}
return false;
}


bool check2(long long int s) {
string str1 = int2string(s);
long long int x = s * s;
string str2 = int2string(x);
for (int i = 0; i < 6; ++i) {
if (str2.find(str1[i]) != string::npos)
return true;//找到了相同的
}
return false;
}

int main() {
long long int num = 203879;
for (; num < 1000000; ++num) {
if (check1(num))//出现重复就跳出
continue;
if (check2(num))//出现重现数字就跳出
continue;
cout << num << endl;
}
return 0;
/* int a = 123456;
int b;
string str;
str = int2string(a);
b = string2int(str);
cout << str[3] << a + b << endl;
return 0;
//测试int2string和string2int能否使用的函数。
*/
}

这一题不难,但是需要积累一些C++知识,比如当find函数找不到时会返回一个string::npos,并且用stringstream去转换int型和string型的函数,这些需要好好地记下来,很多地方都可以用!

  • 第三题

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
//
// Created by ZhiNian on 2019/3/26.
//
/*
标题: 振兴中华

小明参加了学校的趣味运动会,其中的一个项目是:跳格子。

地上画着一些格子,每个格子里写一个字,如下所示:(也可参见p1.jpg)

从我做起振
我做起振兴
做起振兴中
起振兴中华


比赛时,先站在左上角的写着“从”字的格子里,可以横向或纵向跳到相邻的格子里,但不能跳到对角的格子或其它位置。一直要跳到“华”字结束。


要求跳过的路线刚好构成“从我做起振兴中华”这句话。

请你帮助小明算一算他一共有多少种可能的跳跃路线呢?

答案是一个整数,请通过浏览器直接提交该数字。
注意:不要提交解答过程,或其它辅助说明类的内容。

答案是
*/

#include <iostream>

using namespace std;

/*
* 每一个字都有要么向下 要么向右 两个可能
* 可以用递归
*/

int ans = 0;

int fun(int x, int y) {
if (x == 5 || y == 4) {
ans++; //通过全局函数计数
return 1;//通过函数返回计数
} else {
return fun(x + 1, y) + fun(x, y + 1);
}
}

int main() {
cout << "From fun'return:" << fun(1, 1) << endl;
cout << "From int ans:" << 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
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
112
113
114
115
116
117
118
119
120
121
//
// Created by ZhiNian on 2019/3/28.
//
/*

标题: 颠倒的价牌


小李的店里专卖其它店中下架的样品电视机,可称为:样品电视专卖店。

其标价都是4位数字(即千元不等)。

小李为了标价清晰、方便,使用了预制的类似数码管的标价签,只要用颜色笔涂数字就可以了(参见p1.jpg)。

这种价牌有个特点,对一些数字,倒过来看也是合理的数字。如:1 2 5 6 8 9 0 都可以。这样一来,如果牌子挂倒了,有可能完全变成了另一个价格,
比如:1958 倒着挂就是:8561,差了几千元啊!!

当然,多数情况不能倒读,比如,1110 就不能倒过来,因为0不能作为开始数字。

有一天,悲剧终于发生了。某个店员不小心把店里的某两个价格牌给挂倒了。并且这两个价格牌的电视机都卖出去了!

庆幸的是价格出入不大,其中一个价牌赔了2百多,另一个价牌却赚了8百多,综合起来,反而多赚了558元。

请根据这些信息计算:赔钱的那个价牌正确的价格应该是多少?


答案是一个4位的整数,请通过浏览器直接提交该数字。
注意:不要提交解答过程,或其它辅助说明类的内容。

答案是:
*/

#include <iostream>
#include <sstream>
#include <vector>

using namespace std;

string i2s(int x) { //int to string 不解释
stringstream ss;
string y;
ss << x;
ss >> y;
return y;
}

int s2i(string x) { //string to int 不解释
stringstream ss;
int y;
ss << x;
ss >> y;
return y;
}

char change(char x) { //因为1、2、5、8、0翻转后是本身,所以只需要判断6和9,去翻转。
if (x == '6')
return '9';
else if (x == '9')
return '6';
else
return x;
}

string reversal(string str1) {
string str2 = str1;//记住string一定一定一定要初始化,否则默认长度为0,没法存入数据!
// cout << "Test is " << str2.length() << endl;
//以上两行就是刚刚出现的错误,没有用str2=str1去初始化,导致了,后面的赋值无法赋值进去,因为str2长度直接就是为0(可以解开上面注释测试)
for (int i = 3, j = 0; i >= 0; --i, ++j) {//循环返回每一个字符进行翻转
// char x;
// x=change(str1[i]);
//上两行原来也是测试
str2[j] = change(str1[i]);
}
return str2;
}

struct price {
int origin;//记录原始价牌
int after;//记录翻转后的价牌
int temp;//记录翻转后的价牌减去翻转前的价牌的差
};

vector<price> earn;//记录赚了的价牌
vector<price> lose;//记录亏了的价牌

int main() {
//遍历所有的四位数
//判断能否倒过来
//把能倒过来的做减法
// cout << reversal("1958") <<endl;
for (int i = 1000; i < 10000; ++i) {
string str1, str2;//str1存原来的四位数,str2存翻转后的四位数
int s1, s2;//s1是原来四位数,s2是翻转后的四位数
str1 = i2s(i);//int to string
if (str1.find('3') != string::npos || str1.find('4') != string::npos || str1.find('7') != string::npos ||
str1.find('0') == 3)//发现了3、4、7、0在末尾的情况,那么不要此次的i继续循环
continue;
str2 = reversal(str1);//翻转字符
s1 = s2i(str1);//翻转前的数 string to int 可以直接赋值i 但是这么好看 hiahia~
s2 = s2i(str2);//翻转后的数 string to int
int temp = s2 - s1;//差值
if (temp < -200 && temp > -300) {//亏了200多
price p = {s1, s2, temp};//记录进一个缓存p
lose.push_back(p);//p加到lose的后面
}
if (temp > 800 && temp < 900) {//赚了800多
price p = {s1, s2, temp};//记录进一个缓存p
earn.push_back(p);//p加到earn的后面
}
}
for (int j = 0; j < earn.size(); ++j) {//双重循环找差值相加为840的输出
for (int k = 0; k < lose.size(); ++k) {
if (earn[j].temp + lose[k].temp == 558) {
cout << lose[k].origin << " " << lose[k].after << " " << lose[k].temp << ",";
cout << earn[j].origin << " " << earn[j].after << " " << earn[j].temp << endl;
}
}

}
return 0;
}

作为一个积极写注释的人,好像不需要什么过多的语言描述算法了,这个题目让我学会了一点点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;
    }


    请分析代码逻辑,并推测划线处的代码,通过网页提交。
    注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!



    */
    #include <iostream>

    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
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
//
// Created by ZhiNian on 2019/7/16.
//
/*

标题:逆波兰表达式

正常的表达式称为中缀表达式,运算符在中间,主要是给人阅读的,机器求解并不方便。

例如:3 + 5 * (2 + 6) - 1

而且,常常需要用括号来改变运算次序。

相反,如果使用逆波兰表达式(前缀表达式)表示,上面的算式则表示为:

- + 3 * 5 + 2 6 1

不再需要括号,机器可以用递归的方法很方便地求解。

为了简便,我们假设:

1. 只有 + - * 三种运算符
2. 每个运算数都是一个小于10的非负整数

下面的程序对一个逆波兰表示串进行求值。
其返回值为一个结构:其中第一元素表示求值结果,第二个元素表示它已解析的字符数。

struct EV
{
int result; //计算结果
int n; //消耗掉的字符数
};

struct EV evaluate(char* x)
{
struct EV ev = {0,0};
struct EV v1;
struct EV v2;

if(*x==0) return ev;

if(x[0]>='0' && x[0]<='9'){
ev.result = x[0]-'0';
ev.n = 1;
return ev;
}

v1 = evaluate(x+1);
v2 = _____________________________; //填空位置

if(x[0]=='+') ev.result = v1.result + v2.result;
if(x[0]=='*') ev.result = v1.result * v2.result;
if(x[0]=='-') ev.result = v1.result - v2.result;
ev.n = 1+v1.n+v2.n;

return ev;
}


请分析代码逻辑,并推测划线处的代码,通过网页提交。
注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!


*/

#include <iostream>
#include <cstring>

using namespace std;
struct EV {
int result; //计算结果
int n; //消耗掉的字符数
};

struct EV evaluate(char *x) {
struct EV ev = {0, 0};
struct EV v1;
struct EV v2;

if (*x == 0) return ev;

if (x[0] >= '0' && x[0] <= '9') {
ev.result = x[0] - '0';//字符转数字'1'-'0'=1
ev.n = 1;
return ev;
}
//- + 3 * 5 + 2 6 1
v1 = evaluate(x + 1);
v2 = evaluate(x + 1 + v1.n); //填空位置

if (x[0] == '+') ev.result = v1.result + v2.result;
if (x[0] == '*') ev.result = v1.result * v2.result;
if (x[0] == '-') ev.result = v1.result - v2.result;
ev.n = 1 + v1.n + v2.n;

return ev;
}

int main(int argc, const char * argv[]) {
string s="-+3*5+261";
const EV &ev = evaluate((char*)(s.c_str()));
cout<<ev.result<<endl;
return 0;
}

在这一题中,通过调试,通过编译,也没有找到到底是如何填这个空,到最后还是通过一点点的肉眼观察去尝试,然后发现

1
2
3
if (x[0] == '+') ev.result = v1.result + v2.result;
if (x[0] == '*') ev.result = v1.result * v2.result;
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
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
//
// Created by ZhiNian on 2019/7/16.
//

/*

标题:错误票据

某涉密单位下发了某种票据,并要在年终全部收回。

每张票据有唯一的ID号。全年所有票据的ID号是连续的,但ID的开始数码是随机选定的。

因为工作人员疏忽,在录入ID号的时候发生了一处错误,造成了某个ID断号,另外一个ID重号。

你的任务是通过编程,找出断号的ID和重号的ID。

假设断号不可能发生在最大和最小号。

要求程序首先输入一个整数N(N<100)表示后面数据行数。
接着读入N行数据。
每行数据长度不等,是用空格分开的若干个(不大于100个)正整数(不大于100000)
每个整数代表一个ID号。

要求程序输出1行,含两个整数m n,用空格分隔。
其中,m表示断号ID,n表示重号ID

例如:
用户输入:
2
5 6 8 11 9
10 12 9

则程序输出:
7 9


再例如:
用户输入:
6
164 178 108 109 180 155 141 159 104 182 179 118 137 184 115 124 125 129 168 196
172 189 127 107 112 192 103 131 133 169 158
128 102 110 148 139 157 140 195 197
185 152 135 106 123 173 122 136 174 191 145 116 151 143 175 120 161 134 162 190
149 138 142 146 199 126 165 156 153 193 144 166 170 121 171 132 101 194 187 188
113 130 176 154 177 120 117 150 114 183 186 181 100 163 160 167 147 198 111 119

则程序输出:
105 120


资源约定:
峰值内存消耗 < 64M
CPU消耗 < 1000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>,
不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。
*/

/*原始数据连续,输入的时候是乱序的,求出断开的号码和重复的号码*/
#include <iostream>
#include <sstream>
#include <algorithm>

using namespace std;
const int MaxN = 10000;
int line;
int data[MaxN];

void s2i(string &str, int &num) {//字符串转数字
stringstream ss;
ss << str;
ss >> num;
}

int main(int argc, const char *argv[]) {
scanf("%d", &line);
getchar();//一定要记住输入后立马回车再输入别的数据要通过getchar把换行符吃掉,如果不加 那么接收到的第一行数据就是一个换行符
int index = 0;
for (int i = 0; i < line; ++i) {
string s;//定义字符串s
getline(cin, s);//将控制台标准输入流,输入s
istringstream iss(s);//将s封装成iss(istringstream)
string tmp;//再顶一个字符串tmp
while (getline(iss, tmp, ' ')) {//getline自带了分割方法,但是需要注意的是 输入流必须是iss
s2i(tmp, data[index++]);
}
}
// 最终index就是数据的个数
// cout << index << endl;

sort(data, data + index);//排序
int a, b;
for (int i = 1; i < index; ++i) {
if (data[i] == data[i - 1] + 2)a = data[i] - 1;//printf("%d ", data[i] - 1);
if (data[i] == data[i - 1]) b = data[i];//printf("%d", data[i]);
//不能直接输出,坑就在这,万一是先找到了重复的 那么就先输出重复的了 所以要在最后整理格式输出
}
printf("%d %d", a, b);
return 0;
}

这一道题,难点在于,怎么样拆分输入的数据,这个很重要,学会了用while(getline())进行拆分,学会了怎么样字符串转数字的简单函数,怎么样通过sort函数排序。主要是这三点吧。否则换别的方法,拆分就很难了,排序还得自己写,转数字肯定就也是自己写的一个很复杂的函数,时间也浪费了很多。

第八题

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
//
// Created by ZhiNian on 2019/7/16.
//
/*

标题:买不到的数目

小明开了一家糖果店。他别出心裁:把水果糖包成4颗一包和7颗一包的两种。糖果不能拆包卖。

小朋友来买糖的时候,他就用这两种包装来组合。当然有些糖果数目是无法组合出来的,比如要买 10 颗糖。

你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是17。大于17的任何数字都可以用4和7组合出来。

本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。

输入:
两个正整数,表示每种包装中糖的颗数(都不多于1000)

要求输出:
一个正整数,表示最大不能买到的糖数

不需要考虑无解的情况

例如:
用户输入:
4 7
程序应该输出:
17

再例如:
用户输入:
3 5
程序应该输出:
7


资源约定:
峰值内存消耗 < 64M
CPU消耗 < 3000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。

*/

//ax+by=C,不定方程的解 a=4,b=7,C=17 这种情况下,xy实际上有解,7*2+(7-4)==3*7 -1*4
//a,b互质,一定有解且解的数目无穷
//C是gcd(a,b)的倍数,方程一定有解,而且有无穷多解

//条件:一定有解=》a,b互质
//条件2:xy都是大于等于0的整数,在这个限定条件下有的C是无解的,那么C的上界是多少呢?至多是a*b

#include <iostream>
#include <set>

using namespace std;

int main(int argc, const char *argv[]) {
int a, b;
scanf("%d %d", &a, &b);
set<int> ss;
// 枚举a*x+b*y的值,上边界是a*b
for (int x = 0; a * x <= a * b; ++x) {
for (int y = 0; a * x + b * y <= a * b; ++y) {
ss.insert(ss.end(), a * x + b * y);
}
}
for (int i = a * b; i >= 0; --i) {
if (ss.find(i) == ss.end())//i不在set中,那么i就是答案
{
printf("%d\n", i);
break;
}
}
return 0;
}

这一题不难,就是用的是枚举的思想,然后反向扫描找到最大的那一个,但是在老师的教导中,又学会了一个知识点,就是set的运用,set就像是一个集合,它中的元素不允许重复,可以使用set去存入有些可能重复但是重复却没有用的数据从而提高效率。

当然这个题目还有另一种解法:

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <set>

using namespace std;

int main(int argc, const char *argv[]) {
int a, b;
scanf("%d %d", &a, &b);
cout << a * b - a - b << endl;
return 0;
}

就是这么的简单,但是这就是数学基础的问题了,需要熟悉不定方程。

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岁啊。”

    请你写出:小明的较小的妹妹的年龄。


    注意: 只写一个人的年龄数字,请通过浏览器提交答案。不要书写任何多余的内容。

    */

    #include <iostream>
    #include <cmath>

    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种情况,一共有多少种满足要求的算式。

    请填写该数字,通过浏览器提交答案,不要填写多余内容(例如:列出所有算式)。

    */

    #include <iostream>
    #include <sstream>
    #include <cstring>
    #include <algorithm>

    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
    */

    #include <iostream>

    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
    */

    #include <iostream>

    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加,见下图:T2

    就是这么简单,但是呢!!!!!输入答案一定要是 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

    */

    #include <iostream>
    #include <sstream>
    #include <string>

    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()–如果集合为空,返回true

    c++ 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岁就是其中一种可能哦.

    请填写表示可能情况的种数。
    注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

    */

    #include <iostream>

    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的年龄数。
    注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
    */

    #include <iostream>

    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的数字。要求:连续的两个数字不能相邻。
    (左右、上下、对角都算相邻)

    一共有多少种可能的填数方案?

    请填写表示方案数目的整数。
    注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
    */

    #include <iostream>
    #include <stdlib.h>

    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
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
//
// Created by ZhiNian on 2019/4/6.
//

/*
标题:迷宫

X星球的一处迷宫游乐场建在某个小山坡上。
它是由10x10相互连通的小房间组成的。

房间的地板上写着一个很大的字母。
我们假设玩家是面朝上坡的方向站立,则:
L表示走到左边的房间,
R表示走到右边的房间,
U表示走到上坡方向的房间,
D表示走到下坡方向的房间。

X星球的居民有点懒,不愿意费力思考。
他们更喜欢玩运气类的游戏。这个游戏也是如此!

开始的时候,直升机把100名玩家放入一个个小房间内。
玩家一定要按照地上的字母移动。

UDDLUULRUL
UURLLLRRRU
RRUURLDLRD
RUDDDDUUUU
URUDLLRRUU
DURLRLDLRL
ULLURLLRDU
RDLULLRDDD
UUDDUDUDLL
ULRDLUURRR

请你计算一下,最后,有多少玩家会走出迷宫?
而不是在里边兜圈子。

请提交该整数,表示走出迷宫的玩家数目,不要填写任何多余的内容。

如果你还没明白游戏规则,可以参看一个简化的4x4迷宫的解说图:
p4-1.png

*/

#include <iostream>
#include <cstring>

using namespace std;

string data[10];//巧妙地去定义二维数组
int vis[10][10];//记录是否能出去
int ans;

bool fun(int i, int j) {
if (i == -1 || i == 10 || j == -1 || j == 10)//出界
return true;
if (vis[i][j] == 1)//走之前走过的路
return false;
vis[i][j] = 1;
if (data[i][j] == 'U')
return fun(i - 1, j);
else if (data[i][j] == 'D')
return fun(i + 1, j);
else if (data[i][j] == 'L')
return fun(i, j - 1);
else if (data[i][j] == 'R')
return fun(i, j + 1);
else
return false;
// switch (data[i][j]){
// case 'U':
// return fun(i-1,j);
// case 'D':
// return fun(i+1,j);
// case 'L':
// return fun(i,j-1);
// case 'R':
// return fun(i,j+1);
// default:
// return false;
// }


}

int main() {
data[0] = "UDDLUULRUL";
data[1] = "UURLLLRRRU";
data[2] = "RRUURLDLRD";
data[3] = "RUDDDDUUUU";
data[4] = "URUDLLRRUU";
data[5] = "DURLRLDLRL";
data[6] = "ULLURLLRDU";
data[7] = "RDLULLRDDD";
data[8] = "UUDDUDUDLL";
data[9] = "ULRDLUURRR";
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
memset(vis, 0, sizeof(vis));//初始化标记
if (fun(i, j))//false能出去
ans++;
}
}
cout << ans << endl;
return 0;
}
  • 学到了有些时候不一定一直用if if if,还可以switch啊,还有学到了一个函数叫 memset 这个东西太好用了,避免了像以前,还得用循环去初始化一个数组,或许是我没有好好听课,还有就是,当输入二维数组麻烦的时候,可以通过定义一个string的一维数组,去充当二维数组使用!