《C++编程这样学》第八章:二维数组- 加油站题解

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。

113569
1247810
1056911
86472
1510112025
【题解代码】
#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)

  1. 若K−1在第一行但不在最后一列,则将K填在最后一行,K−1所在列的右一列。
  2. 若K−1在最后一列但不在第一行,则将K填在第一列,K−1所在行的上一行。
  3. 若K−1在第一行最后一列,则将K填在K−1的正下方;
  4. 若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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值