PS/문제풀이

[BOJ] 2045 - 마방진 (C++)

꼬두람2 2021. 10. 27. 04:22

 

https://www.acmicpc.net/problem/2045

 

2045번: 마방진

3 by 3 크기의 마방진을 생각하자. 마방진이란 가로, 세로, 대각선 위의 수들의 합이 모두 같은 성질을 가지고 있다. 몇 가지 마방진을 예로 들면 다음과 같다. 생일빵을 맞은 정신을 잃은 동주와

www.acmicpc.net


풀이

 보편적으로는 세로든 가로든 대각선이든 한 줄의 합을 구했다. 구한 합을 이용하여 지워진 곳의 값을 구하여 바꾸어 주었다. 

 지워진 값을 구할 때 조심해야 할 부분이 있다.

0 0  
    0
     

첫번째 행을 보면 지워진 곳이 두 곳이 있다. 이럴 경우에는 미지수가 두 개이기 때문에 지워진 값을 구할 수 없다. 따라서 이 때는 열을 이용해 지워진 값을 구하도록 구현했다.

 

 

 

 위와 같은 방식으로 구현했을 때, 예외 case가 발생한다.

0    
  0  
    0

 위처럼 한 대각선의 수를 모두 지워버린 상태라면 한 줄의 합을 구할 수 없다. 이 경우에는 방정식을 세워서 지워진 값을 구했다. 예제 입력으로 방정식을 세워보면,

x 12 12
16 x+4 4
8 8 x+8

 첫번째 행의 지워진 값을 x라고 두고, 행의 합을 기준으로 다른 지워진 값들을 x에 대해 표현한다. 그럼 대각선의 합은 1행의 합과 같기 때문에 3x + 12 = x + 24,  2x = 12, 즉 x = 6 임을 구할 수 있다.

 

 이 방정식을 일반화하여 코드를 구현했다.


코드

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <climits>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <cstring>
#include <map>
#include <functional>

using namespace std;
using ll = long long;

int arr[10][10];

int main(void) {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	// 마방진 입력
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			cin >> arr[i][j];
		}
	}
	
	// 예외 : 대각선을 모두 까먹었을 때
	if (!arr[0][0] && !arr[1][1] && !arr[2][2]) {
		vector<int>v;
		v.push_back(arr[0][1] + arr[0][2]);
		v.push_back(arr[1][0] + arr[1][2]);
		v.push_back(arr[2][0] + arr[2][1]);
		int temp = v[0] - v[1] + v[0] - v[2];
		temp = v[0] - temp;
		arr[0][0] = temp / 2;
		arr[1][1] = arr[0][0] + v[0] - v[1];
		arr[2][2] = arr[0][0] + v[0] - v[2];
		
	}

	if (!arr[0][2] && !arr[1][1] && !arr[2][0]) {
		vector<int>v;
		v.push_back(arr[0][0] + arr[0][1]);
		v.push_back(arr[1][0] + arr[1][2]);
		v.push_back(arr[2][1] + arr[2][2]);
		int temp = v[0] - v[1] + v[0] - v[2];
		temp = v[0] - temp;
		arr[0][2] = temp / 2;
		arr[1][1] = arr[0][2] + v[0] - v[1];
		arr[2][0] = arr[0][2] + v[0] - v[2];

	}



	int total = 0;
	// 한 줄의 합 구하기
	// 가로
	for (int i = 0; i < 3; i++) {
		int temp = 0;
		for (int j = 0; j < 3; j++) {
			temp += arr[i][j];
		}
		total = max(total, temp);
	}
	// 세로
	for (int i = 0; i < 3; i++) {
		int temp = 0;
		for (int j = 0; j < 3; j++) {
			temp += arr[j][i];
		}
		total = max(total, temp);
	}
	// 대각선
	total = max(total, arr[0][0] + arr[1][1] + arr[2][2]);
	total = max(total, arr[0][2] + arr[1][1] + arr[2][0]);
	// 미지값 구하기
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			int temp = 0;
			if (arr[i][j]) continue;
			// i 행에 0이 한 개 인지 확인
			bool chk_i = 1;
			for (int k = 0; k < 3; k++) {
				if (k == j) continue;
				if (!arr[i][k]) chk_i = 0;
			}
			
			if (chk_i) {
				for (int k = 0; k < 3; k++) {
					temp += arr[i][k];
				}
				arr[i][j] = total - temp;
				continue;
			}
			// j 열에 0이 한개 인지 확인 필요 x
			for (int k = 0; k < 3; k++) {
				temp += arr[k][j];
			}
			arr[i][j] = total - temp;
		}
	}
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			cout << arr[i][j] << ' ';
		}
		cout << '\n';
	}
}

'PS > 문제풀이' 카테고리의 다른 글

[BOJ] 14717 - 앉았다 (c++)  (7) 2021.11.19
[BOJ] 14923 - 미로 탈출 (C++)  (9) 2021.11.15