1. 点阵压缩
题目链接:http://csp.magu.ltd/problem/J0857
【问题描述】
一个汉字可以看做由n * n的0和1的点阵图组成,依照以下规则可以将点阵图压缩成一个压缩码:
从汉字点阵图的第一行第一个符号开始,按由左到右,从上到下的顺序扫描,得到若干个数,第1个数表示连续有几个0,第2个数表示接下来连续有几个1,第3个数表示再接下来连续有几个0,第4个数表示再接下来连续有几个1,以此类推…
例如,以下汉字点阵图:
0 0 0 1 0 0 0
0 0 0 1 0 0 0
0 0 0 1 1 1 1
0 0 0 1 0 0 0
0 0 0 1 0 0 0
0 0 0 1 0 0 0
1 1 1 1 1 1 1
对应的压缩码是: 3 1 6 1 6 4 3 1 6 1 6 1 3 7(整数表示交替表示0和1 的个数)。
编写程序,输入一个汉字的点阵图,输出其压缩码。
【题解代码】
#include <iostream>
using namespace std;
int a[10010], b[10010];
int main()
{
int n, m = 0;
cin >> n;
for (int i = 1; i <= n * n; i++)
{
cin >> a[i];
}
int len = 1;
if (a[1] != 0)
{
cout << 0 << " ";
}
for (int i = 1; i <= n * n; i++)
{
if (a[i] == a[i + 1])
len++;
else
{
b[++m] = len;
len = 1;
}
}
for (int i = 1; i <= m; i++)
{
cout << b[i] << " ";
}
return 0;
}
2. 素数联盟
题目链接:http://csp.magu.ltd/problem/J0858
【问题描述】
在一个矩阵中,如果一个素数的上、下、左、右、左上、左下、右上、右下都是素数,则形成以该素数为盟主的素数联盟。
编写程序,输入一个n行m列的数组表示的矩阵,统计该矩阵中的素数联盟有多少个。
【题解代码】
#include <iostream>
using namespace std;
int dx[] = {0,1,0,-1,1,1,-1,-1};
int dy[] = {1,0,-1,0,1,-1,1,-1};
int a[110][110];
bool is_prime(int n)
{
for (int i = 2; i * i <= n; i ++) {
if (n % i == 0) return false;
}
return true;
}
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
cin >> a[i][j];
int cnt = 0;
for (int i = 2; i < n; i ++) {
for (int j = 2; j < m; j ++) {
if (is_prime(a[i][j])) {
bool f = true;
for (int k = 0; k < 8; k ++) {
int nx = i + dx[k], ny = j + dy[k];
if (!is_prime(a[nx][ny])) f = false;
}
if (f) cnt ++;
}
}
}
cout << cnt << endl;
return 0;
}
3. 找朋友
题目链接:http://csp.magu.ltd/problem/J0859
【问题描述】
每个人都喜欢和自己同龄的人交朋友,现在有一个n行m列的队伍,队伍中每个人的年龄都是整数,每个人只能在与其同一行、同一列的人中交朋友,编写程序,统计并输出每个人能交到多少个朋友。
比如:一个4行4列的矩阵(为叙述方便,用矩阵表示队伍)如图8-10的左图所示,该矩阵中每个数字代表了一个同学的年龄,每个人能找到的朋友数如图8-10的右图所示。
图8-10中,第2行第2列的人的年龄是9岁,他所在的第2行中没有与他同龄的,他所在的第2列中有一个和他同龄的人,因此他可以交到1个朋友。
【题解代码】
#include <iostream>
using namespace std;
int a[110][110];
int b[110][110];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
cin >> a[i][j];
}
}
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
int cnt = 0;
for (int col = 1; col <= m; col ++) {
if (a[i][col] == a[i][j] && col != j) cnt ++;
}
for (int row = 1; row <= n; row ++) {
if (a[row][j] == a[i][j] && row != i) cnt ++;
}
cout << cnt << " ";
}
cout << endl;
}
return 0;
}
4. 图像旋转
题目链接:http://csp.magu.ltd/problem/J0860
【问题描述】
编写程序,输入一个n行m列的黑白图像的点阵,将它顺时针旋转90度后输出。
【题解代码】
#include <iostream>
using namespace std;
int a[110][110];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
cin >> a[i][j];
for (int j = 1; j <= m; j ++) {
for (int i = n; i >= 1; i --) {
cout << a[i][j] << " ";
}
cout << endl;
}
return 0;
}
5. 对称矩阵
题目链接:http://csp.magu.ltd/problem/J0861
【问题描述】
对称矩阵有如图8-11所示的A、B、C、D四种对称形式,其中C、D两种形式仅对方阵有效。
编写程序,输入一个矩阵的各个元素的值,判断该矩阵属于哪种对称形式,如果属于多种对称形式,按A~D的顺序输出。
【题解代码】
#include <iostream>
using namespace std;
int a[110][110];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
cin >> a[i][j];
int cnt = 0; // 表示当前有几种对称方式,cnt==0 NO
bool f = true; // 它是对称的
// 上下对称
for (int i = 1; i <= n/2; i ++) {
for (int j = 1; j <= m; j ++) {
if (a[i][j] != a[n-i+1][j]) { // a[1][j] - a[4][j]
f = false;
break;
}
}
}
if (f) cout << "A ", cnt ++;
// 左右对称
f = true;
for (int j = 1; j <= m/2; j ++) {
for (int i = 1; i <= n; i ++) {
if (a[i][j] != a[i][m-j+1]) {
f = false;
break;
}
}
}
if (f) cout << "B ", cnt ++;
if (n == m) // C和D仅对方阵有效
{
// 主对角线对称
f = true;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= i; j ++) {
if (a[i][j] != a[j][i]) {
f = false;
break;
}
}
}
if (f) cout << "C ", cnt ++;
// 副对角线
f = true;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n-i+1; j ++) {
if (a[i][j] != a[n-j+1][n-i+1]) {
f = false;
break;
}
}
}
if (f) cout << "D", cnt ++;
}
if (cnt == 0) cout << "NO";
return 0;
}
6. 寻找鞍点
题目链接:http://csp.magu.ltd/problem/J0862
【问题描述】
编写程序,输入一个5行5列的矩阵,每行只有一个最大值,每列只有一个最小值,寻找这个矩阵的鞍点。鞍点是指矩阵中的一个元素,它是所在行的最大值,并且是所在列的最小值。例如,下面所示的矩阵中,第4行第1列的元素就是鞍点,其值为8。
11 | 3 | 5 | 6 | 9 |
---|---|---|---|---|
12 | 4 | 7 | 8 | 10 |
10 | 5 | 6 | 9 | 11 |
8 | 6 | 4 | 7 | 2 |
15 | 10 | 11 | 20 | 25 |
【题解代码】
#include <iostream>
using namespace std;
int a[110][110];
int main()
{
for (int i = 1; i <= 5; i ++)
for (int j = 1; j <= 5; j ++)
cin >> a[i][j];
bool f;
int maxx, x, y;
// 按行遍历
for (int i = 1; i <= 5; i ++)
{
f = true;
maxx = -2e9;
for (int j = 1; j <= 5; j ++) {
if (a[i][j] > maxx) maxx = a[i][j], x = i, y = j; // 记录最大值的信息
}
// 遍历最大值所在的这一列
for (int k = 1; k <= 5; k ++) {
if (a[k][y] < maxx) {
f = false;
break;
}
}
if (f) break;
}
if (f) {
cout << x << " " << y << " " << maxx;
}
else cout << "not found";
return 0;
}
7. 炸弹人
题目链接:http://csp.magu.ltd/problem/J0863
【问题描述】
炸弹人是一个非常经典的小游戏,游戏在一个n行m列的网格盘内进行,这个网格盘的某些格子中设置了障碍,炸弹人可以在任何一个没有障碍的格子中放置炸弹,炸弹爆炸的威力可以向8个方向(上、下、左、右、左上、右上、左下、右下)延伸,直至到达障碍或到达边界,如图8-12所示,在第3行、第4列的格子中放置炸弹,其威力能覆盖15个格子。
对于一个n行m列的网格盘,将炸弹放到p行q列的格子中,编写程序,计算并输出炸弹威力能覆盖的格子数量。
【题解代码】
#include <iostream>
using namespace std;
int a[110][110];
int dx[] = {0,1,0,-1,1,1,-1,-1};
int dy[] = {1,0,-1,0,1,-1,1,-1};
int main()
{
int n, m, p, q;
cin >> n >> m >> p >> q;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
cin >> a[i][j];
}
}
int cnt = 1; // 包括一开始炸弹所在的位置
for (int k = 0; k < 8; k ++)
{
int nx = p + dx[k], ny = q + dy[k];
while (nx >= 1 && nx <= n && ny >= 1 && ny <= m && a[nx][ny] == 0)
{
cnt ++;
nx += dx[k], ny += dy[k];
}
}
cout << cnt;
return 0;
}
8. 神奇的幻方(NOIP2015 提高组)
题目链接:http://csp.magu.ltd/problem/J0864
【问题描述】
幻方是一种很神奇的 N*N
矩阵:它由数字 1,2,3,……,N*N
构成,且每行、每列及两条对角线上的数字之和都相同。当N为奇数时,我们可以通过以下方法构建一个幻方:
首先将1写在第一行的中间,然后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N)
:
- 若K−1在第一行但不在最后一列,则将K填在最后一行,K−1所在列的右一列。
- 若K−1在最后一列但不在第一行,则将K填在第一列,K−1所在行的上一行。
- 若K−1在第一行最后一列,则将K填在K−1的正下方;
- 若K−1既不在第一行,也不在最后一列,如果K−1的右上方还未填数,则将K填在K−1的右上方,否则将K填在K−1的正下方。
编写程序,输入一个奇数N,按上述方法构造N*N
的幻方。
【题解代码】
#include <iostream>
using namespace std;
int a[110][110];
int main()
{
int n;
cin >> n;
int i = 1, j = n/2+1;
a[i][j] = 1;
for (int k = 2; k <= n*n; k ++)
{
if (i == 1 && j != n) i = n, j ++;
else if (i != 1 && j == n) i --, j = 1;
else if (i == 1 && j == n) i ++;
else {
if (a[i-1][j+1]) i ++;
else i --, j ++;
}
a[i][j] = k;
}
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= n; j ++) {
cout << a[i][j] << " ";
}
cout << endl;
}
return 0;
}