目录
B-4 方格填数
2014 年哈佛-麻省理工数学竞赛中一道题是这样的:将正整数 1, 2, ..., 64 填入 8×8 的方格棋盘中,使得对任何 1≤i<64,i 和 i+1 都必须填在两个具有公共边的方格中。求棋盘上对角线中所填数的和的最大值。(注意:两个对角线都要考虑;64 和1 也必须填在两个具有公共边的方格中。)
这题有点难…… 幸好我们并不要求你写程序解决这个问题。
你的任务是:对任一给定的数字填充方案,判定其是否满足填充的条件,并且在所有给出的方案中,找出满足条件的、且对角线数字和最大的那个方案。
输入格式:
输入在一行中首先给出两个正整数 n(≤100) 和 m(≤20),分别为棋盘的规模(即棋盘有 n×n 个方格)和输入的方案数量。因为容易证明奇数 n 一定不存在满足条件的解,所以题目保证给出的 n 都是偶数。
随后给出 m 个填充方案,每个方案占 n 行,每行 n 个不超过 n2 的数字。同行数字间以空格分隔。
输出格式:
在一行中首先输出满足条件的、且对角线数字和最大的方案数。随后一行中按照递增序输出这些方案的编号(编号按输入的顺序从 1 到 m)。
注意每行数字间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
4 5
16 1 2 3
15 14 13 4
10 11 12 5
9 8 7 6
16 1 2 3
15 14 13 4
10 11 12 5
9 8 7 10
15 16 1 2
14 13 4 3
11 12 5 6
10 9 8 7
3 4 5 6
2 13 12 7
1 14 11 8
16 15 10 9
10 5 4 3
7 12 13 2
8 11 14 1
9 6 15 16
输出样例:
2
1 4
条件提取
- (注意:两个对角线都要考虑;64 和1 也必须填在两个具有公共边的方格中。)
- 两个正整数 n(≤100) 和 m(≤20)
- 将正整数 1, 2, ..., 64 填入 8×8 的方格棋盘中,使得对任何 1≤i<64,i 和 i+1 都必须填在两个具有公共边的方格中。
- 。求棋盘上对角线中所填数的和的最大值。
- 在一行中首先输出满足条件的、且对角线数字和最大的方案数。随后一行中按照递增序输出这些方案的编号(编号按输入的顺序从 1 到 m)。
注意每行数字间以 1 个空格分隔,行首尾不得有多余空格。
思路
当n为4时,最大的元素为16 , 16需要和1相邻 , 只需要判断每个元素的上下左右四个位置元素即可
j 为行遍历变量 k 为列遍历变量 , i从0到n , j从0到n
int x[4] = {j - 1, j , j, j + 1}, y[4] = {k, k - 1, k + 1, k}; x,y数组为上下左右四个相邻元素的位置下标 . 如果矩阵合法则判断两个对角线元素之和是否大于max 大于则清空原有最大和编号容器 , 然后把本编号添加进去
最后输出合法矩阵总数,然后按增序输出编号 注意即便总数为0也要再输出一个空行
#include<bits/stdc++.h>
using namespace std;
int main(void) {
int n, m, max = 0;
map<int, int> v;
scanf("%d %d", &n, &m);
getchar();
for (int i = 0; i < m; ++i) {
int a[n][n];
for (int j = 0; j < n; ++j)
for (int k = 0; k < n; ++k) {
scanf("%d", &a[j][k]);
getchar();
}
bool F = 1;
for (int j = 0; j < n; ++j)
for (int k = 0; k < n; ++k) {
int x[4] = {j - 1, j , j, j + 1}, y[4] = {k, k - 1, k + 1, k};
bool f = 0;
for (int q = 0; q < 4; ++q)
//若坐标合法
if (x[q] > -1 && x[q] < n && y[q] > -1 && y[q] < n)
if (a[j][k] == a[x[q]][y[q]] % (n * n) + 1) {
f = 1;
break;
}
if (!f) {
F = 0;
break;
}
}
if (F) {
int sum = 0;
for (int j = 0; j < n; ++j) {
sum += a[j][j];
sum += a[n - j - 1][j];
}
if (sum > max) {
max = sum;
v.clear();
v[i + 1] = 1;
} else if (sum == max) v[i + 1] = 1;
}
}
bool f = 1;
printf("%d\n", v.size());
for (auto a : v) {
printf("%s%d", f ? "" : " ", a.first);
f = 0;
}
printf("\n");
return 0;
}
B-5 堆栈中的最大值
堆栈是一种后进先出的线性结构。本题要求你在实现普通堆栈的进栈(Push)和出栈(Pop)功能时,外加一个查看最大值(PeekMax)的功能。重点是,这个额外的功能不能影响整个堆栈的操作效率。
输入格式:
输入第一行首先给出一个正整数 n (≤105),是堆栈操作的数量。随后 n 行,每行给出一个操作,格式为:
Push X
表示将值为X
的元素入栈,其中X
是绝对值不超过 230 的整数;Pop
表示将栈顶元素出栈;PeekMax
表示要求返回此刻堆栈中最大元素的值。
输出格式:
对输入中的每个操作,按照要求执行操作。对每个 Pop
,在一行中输出出栈的元素值;对每个 PeekMax
,在一行中输出此刻堆栈中最大元素的值。若执行 Pop
或 PeekMax
时堆栈是空的,则对应输出 ERROR
,并且不执行该操作。
题目保证至少有一行输出。
输入样例:
11
Pop
Push 34
Push 28
PeekMax
Push 84
PeekMax
Pop
PeekMax
Pop
Pop
PeekMax
输出样例:
ERROR
34
84
84
34
28
34
ERROR
思路
双栈 一个存储元素的栈 另一个存储最大值的栈
如果push的元素大于等于上一个最大元素值 则入存储最大值的栈中 小于的不用入存储最大值的栈 无论push的元素与上一个最大元素值大小关系如何都必须入存储元素的栈
出栈顶元素时候如果是最大值元素 则对应存储最大值的栈也要出栈顶元素
输出栈内最大值的时候,只需要输出存储最大值的栈的栈顶元素
#include<bits/stdc++.h>
using namespace std;
int main(void) {
int n, t = 0;
scanf("%d", &n);
getchar();
string s;
queue<int> q;
vector<int> v;
int a[n], b[n], top = -1, mtop = -1;
for (int i = 0; i < n; ++i) {
cin >> s;
if (s == "Push") {
cin >> t;
if (top == -1)
b[++mtop] = t;
else if (t >= b[mtop]) b[++mtop] = t;
a[++top] = t;
} else if (s == "PeekMax") {
if (top == -1) printf("ERROR\n");
else printf("%d\n", b[mtop]);
} else if (s == "Pop") {
if (top == -1) printf("ERROR\n");
else {
printf("%d\n", a[top]);
if (a[top] == b[mtop]) --mtop;
--top;
}
}
}
return 0;
}