May 05, 2020
문제
스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루어진 정사각형 판 위에서 이뤄지는데, 게임 시작 전 몇 몇 칸에는 1부터 9까지의 숫자 중 하나가 쓰여 있다.
나머지 빈 칸을 채우는 방식은 다음과 같다.
- 각각의 가로줄과 세로줄에는 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
- 굵은 선으로 구분되어 있는 3x3 정사각형 안에도 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
- 위의 예의 경우, 첫째 줄에는 1을 제외한 나머지 2부터 9까지의 숫자들이 이미 나타나 있으므로 첫째 줄 빈칸에는 1이 들어가야 한다.
또한 위쪽 가운데 위치한 3x3 정사각형의 경우에는 3을 제외한 나머지 숫자들이 이미 쓰여있으므로 가운데 빈 칸에는 3이 들어가야 한다. 이와 같이 빈 칸을 차례로 채워 가면 다음과 같은 최종 결과를 얻을 수 있다.
게임 시작 전 스도쿠 판에 쓰여 있는 숫자들의 정보가 주어질 때 모든 빈 칸이 채워진 최종 모습을 출력하는 프로그램을 작성하시오.
입력
아홉 줄에 걸쳐 한 줄에 9개씩 게임 시작 전 스도쿠판 각 줄에 쓰여 있는 숫자가 한 칸씩 띄워서 차례로 주어진다. 스도쿠 판의 빈 칸의 경우에는 0이 주어진다. 스도쿠 판을 규칙대로 채울 수 없는 경우의 입력은 주어지지 않는다.
출력
모든 빈 칸이 채워진 스도쿠 판의 최종 모습을 아홉줄에 걸쳐 한 줄에 9개씩 한 칸씩 띄워서 출력한다.
스도쿠 판을 채우는 방법이 여럿인 경우는 그 중 하나만을 출력한다.백트래킹으로 해결할 수 있었다. 제일 까다로웠던 부분은 3X3 구역에 겹치는 숫자가 있는지 확인하는 것이었는데, 어떤 좌표의 구간 위치를 구하기 위해서 좌표를 3으로 나눈 몫에 다시 3을 곱하는 방식으로 0, 3, 6 중 하나가 나오도록 했다. 백트래킹을 진행하면서 재귀를 끝내는 조건으로 모든 0이 들어있는 좌표가 다른 숫자로 채워졌는지 확인했는데, 이를 위해서 처음에 입력을 받을 때 0이 들어있다면 별도의 배열에 그 좌표를 저장하도록 했다.
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
bool cmp (string a, string b){
if (a.size() < b.size()) return true;
else if (a.size() > b.size()) return false;
else{
int sumA = 0, sumB = 0;
for (int i = 0 ; i < a.size() ; i++){
if(isdigit(a[i])) sumA += (a[i]-'0');
if(isdigit(b[i])) sumB += (b[i]-'0');
}
if (sumA < sumB) return true;
else if (sumA > sumB) return false;
else {
return a < b;
}
}
}
int main (){
int N;
vector<string> serial;
cin >> N;
while(N--){
string str;
cin >> str;
serial.push_back(str);
}
sort(serial.begin(), serial.end(), cmp);
for (auto s : serial){
cout << s << "\n";
}
return 0;
}