Xin gợi ý cách in ma trận có dạng như sau

Tình hình là em đang thử in một ma trận và kết quả mong muốn có dạng như sau:

n = 4
4 4 4 4 4 4 4
4 3 3 3 3 3 4
4 3 2 2 2 3 4
4 3 2 1 2 3 4
4 3 2 2 2 3 4
4 3 3 3 3 3 4
4 4 4 4 4 4 4 

Nhưng thực tế khi em code thì nó lại ra như thế này:

4 4 4 4 4 4 4
4 3 3 3 3 3 4
4 4 2 2 2 4 4
4 4 4 1 4 4 4
4 4 4 4 4 4 4
4 4 4 4 4 4 4
4 4 4 4 4 4 4 

Và thật sự là em không biết phải làm thế nào nữa @@

Code của em đây ạ:

#include <stdio.h>
#define MAX 50

void InMang(const int array[MAX][MAX], const int length) {
	for (int dong = 0; dong < length; dong++) {
		for (int cot = 0; cot < length; cot++) {
			printf("%4d", array[dong][cot]);
		}
		printf("\n");
	}
}

void DatGiaTri(int array[MAX][MAX], const int length, const int number) {
	for (int dong = 0; dong < length; dong++) {
		for (int cot = 0; cot < length; cot++) {
			array[dong][cot] = number;
		}
	}
}

void TaoMang(int array[MAX][MAX], const int length) {
	for (int dong = 1; dong < length - 1; dong++) {
		for (int cot = dong; cot < length - dong; cot++) {
			array[dong][cot] = array[dong][cot] - dong;
		}
	}
}

int main() {
	int array[MAX][MAX];
	int number = 4;
	int length = (number * 2) - 1;

	DatGiaTri(array, length, number);

	TaoMang(array, length, number);

	InMang(array, length);

	return 0;
}

Em rất mong gợi ý của mọi người ạ :frowning:

1 Like

Tình hình là em đã giải được bài này:

#include <stdio.h>
#include <stdlib.h>

#define MAX 100

// Copy dòng
void copy(int mang[MAX][MAX], const int length, int from, int to)
{
    for (int i = 0; i < length; i++)
    {
        mang[to][i] = mang[from][i];
    }
}

// Tạo giá trị
void matran(int mang[MAX][MAX], const int length, const int number)
{
    // Chạy từ 0 -> đến nửa ma trận
    for (int hang = 0; hang <= length / 2; hang++)
    {
        for (int cot = hang; cot < length - hang; cot++)
        {
            if (hang >= 1 && cot <= hang)
            {
                for (int i = 0; i < cot; i++)
                {
                    mang[hang][i] = mang[hang - 1][i];
                    mang[hang][length - i - 1] = mang[hang - 1][i];
                }
            }
            mang[hang][cot] = number - hang;
        }
    }
    // Copy nửa ma trận trên sang nửa ma trận dưới
    for (int hang = (length / 2) + 1, i = length / 2 - 1; hang < length, i >= 0; ++hang, --i)
    {
        copy(mang, length, i, hang);
    }
}

void print(const int mang[MAX][MAX], const int length)
{
    for (int hang = 0; hang < length; ++hang)
    {
        for (int cot = 0; cot < length; ++cot)
        {
            printf("%3d", mang[hang][cot]);
        }
        printf("\n");
    }
}

int main()
{
    int mang[MAX][MAX];
    int number = 3;
    int length = (number * 2) - 1;

    matran(mang, length, number);

    print(mang, length);

    return 0;
}

Nhưng em nhìn code có vẻ ngu ngu :frowning:
Không biết ai có lòng tốt cho em một cách giải tốt hơn được không ạ?

1 Like

Ý tưởng của mình là: Tạo 1/4 mảng đó thôi. Sau đó lấy đối xứng để in ra

Ưu điểm: Tiết kiệm bộ nhớ hơn 4 lần

Code tham khảo:

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 50;

int a[N][N];

#define FOR(i,a,b) for (int i=(a),_b_=(b);i<_b_;i++)
#define elif else if
int main(){
	int n = 4;
	// Tạo 1/4 mảng ở góc trên bên trái
	FOR(i,0,n){
		FOR(j,0,n){
			a[i][j] = n - min(i, j);
		}
	}
        
    // In ra, với 3/4 còn thiếu, in ra bằng cách lấy đối xứng trục.
	int m = 2*n - 1;
	FOR(i,0,m){
		FOR(j,0,m){
			cout << a[min(i, m-i-1)][min(j, m-j-1)] << " ";
		}
		cout << "\n";
	}
}

Output với n = 6

6 6 6 6 6 6 6 6 6 6 6
6 5 5 5 5 5 5 5 5 5 6
6 5 4 4 4 4 4 4 4 5 6
6 5 4 3 3 3 3 3 4 5 6
6 5 4 3 2 2 2 3 4 5 6
6 5 4 3 2 1 2 3 4 5 6
6 5 4 3 2 2 2 3 4 5 6
6 5 4 3 3 3 3 3 4 5 6
6 5 4 4 4 4 4 4 4 5 6
6 5 5 5 5 5 5 5 5 5 6
6 6 6 6 6 6 6 6 6 6 6
4 Likes

Cách của mình là quan sát một chút rồi rút ra quy luật.

Nội dung quy luật gần giống như trong topic này mình đã trình bày (phần Cách bác học - dựa vào hệ toạ độ), chỉ cần quan sát và sửa số lại cho phù hợp với đề.

Ưu điểm:

  • Không cần quá nhiều if else hay vòng for phức tạp, chỉ cần 2 vòng for lồng nhau.

  • Tiết kiệm bộ nhớ, chỉ cần thêm O(1) mem (2 biến chạy).

Nhược điểm:

  • Có mùi toán :grin:

  • Code có vẻ khó đọc :grin:

Mã giả
for (x: -(n - 1) -> n - 1) {
    for (y: -(n - 1) -> n - 1)
        print(max(abs(x), abs(y)) + 1)

    print('\n')
}
10 Likes

chùm cuối rồi :joy:

20 chả

1 Like

phân tích 1 chút trước khi bắt đầu viết code
với n ta có ma trận là (2x-1)x(2n-1), để dễ hơn thì xét n = 4
đánh index từ 0 nhé
xét dong giữa (dòng 3, tức la dòng n - 1)
chỉ số cột (j): 0 1 2 3 4 5 6
giá trị tài dòng (v): 4 3 2 1 2 3 4
công thức:
v = n - j, (nếu n - j >= 1, tức là phần giảm 4 3 2 1),
v = n - (6-j) = n + j - 6,
số 6 = 2*n - 2 nên qua nạp ra thì v = j - n + 2 (nếu j - n + 2 >= 1, tức là phần tăng 1 2 3 4, số ở giữa lấy bên nào cũng đúng vì nó đối xứng)

để gọn thì giá trị tại dòng n-1 cột jv(n-1, j) = max(n - j, j + 2 - n)

tương tự giá trị tại dòng i cột n-1v(n-1, j) = max(n - i, i + 2 - n)

tới đây viết 1 cái hàm getValue(n, x) => max(n - x, x + 2 - n), vì cả dòng giữa hay cột giữa đều giống công thức

đó là chữ thập ở giữa ma trận, giờ xét tới v(i, j) bất kì
tinh ý một chú sẽ thấy, giá trị đó là max của 2 giá trị mà mình chiếu tới chữ thập mình đã tính lúc nãy

4 4 4 4 4 4 4
4 3 3 3 3 3 4
4 3 2 2 2 3 4
4 3 2 1 2 3 4
4 3 2 2 2 3 4
4 3 3 3 3 3 4
4 4 4 4 4 4 4

ví dụ ví trí dòng 1 cột 4 trên ma trận tức là v(1, 4)
vị trí đó chiếu xuống dòng 3 thì thấy có gía trị v(3, 4) là 2
vị trí đó chiếu qua cột 3 thì giá trị của nó là v(1, 3) là 3
lấy max là 3

vậy với vị trí bất kì
v(i, j) = max(v(3, j), v(i, 3)) = max(v(n-1, j), v(i, n-1))

v(n-1, x) = v(x, n-1) = max(n-x, x + 2 - n)
suy ra luôn cho dễ
v(i, j) = max(n - i, i + 2 - n, n - j, j + 2 - n )

5 Likes

Em cảm ơn mấy anh đã giúp đỡ ạ :heart_eyes:

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?