https://www.acmicpc.net/problem/2580
2580번: 스도쿠
스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루
www.acmicpc.net
- 재귀를 이용한 백트래킹을 사용해야 풀 수 있는 문제다.
- 나는 문제를 풀었지만 452ms 가 나왔고 채점 현황에서 다른 사람들과 비교했을 때 매우 느린 수준이다.
- 따라서 다시 문제를 분석하여 코드를 개선할 필요가 있다.
- 나는 0이 나오는 위치를 pair<>로 저장하여 사용했다.
- 가장 예제로 좋은 것은 9 x 9 의 칸이 모두 '0' 일 경우 일까?
더보기
#include <iostream>
#include <vector>
#include <deque>
using namespace std;
vector<vector<int>> inputList;
typedef pair<int, int> ZERO_POS;
deque<ZERO_POS> zeroPosList;
// debug
#define debug_m 0
// method
void Print();
void Sudoku(int x, int y);
bool CheckV(int x, int y, int value);
bool CheckH(int x, int y, int value);
bool CheckNemo(int x, int y, int value);
int main()
{
// init
std::ios::sync_with_stdio(false);
// input
for (int x = 0; x < 9; x++)
{
vector<int> tempList;
for (int y = 0; y < 9; y++)
{
int input = 0;
(void)scanf("%d", &input);
if (0 == input)
{
ZERO_POS zeroPos(x, y);
zeroPosList.push_back(zeroPos);
}
tempList.push_back(input);
}
inputList.push_back(tempList);
}
// Calc
ZERO_POS startPos = zeroPosList.front();
zeroPosList.pop_front();
Sudoku(startPos.first, startPos.second);
// print
Print();
return 0;
}
void Print()
{
#if debug_m
printf("\n");
#endif
// Print
for (auto x : inputList)
{
for (auto y : x)
printf("%d ", y);
printf("\n");
}
}
void Sudoku(int x, int y)
{
for (int value = 1; value <= 9; value++)
{
const bool isOkH = CheckH(x, y, value);
if (false == isOkH)
continue;
const bool isOkV = CheckV(x, y, value);
if (false == isOkV)
continue;
const bool isOkNemo = CheckNemo(x, y, value);
if (false == isOkNemo)
continue;
else
{
inputList[x][y] = value;
#if debug_m
Print();
#endif
// stop
if (true == zeroPosList.empty())
return;
// next
ZERO_POS nextZeroPos = zeroPosList.front();
zeroPosList.pop_front();
Sudoku(nextZeroPos.first, nextZeroPos.second);
// stop
if (true == zeroPosList.empty())
return;
zeroPosList.push_front(nextZeroPos);
inputList[x][y] = 0;
}
}
}
bool CheckV(int x, int y, int value)
{
bool numCheck[10] = { false, };
for (int idx = 0; idx < 9; idx++)
{
if (x == idx)
continue;
const int arrVal = inputList[idx][y];
if (false == numCheck[arrVal])
{
numCheck[arrVal] = true;
}
}
if (true == numCheck[value])
return false;
return true;
}
bool CheckH(int x, int y, int value)
{
bool numCheck[10] = { false, };
for (int idx = 0; idx < 9; idx++)
{
if (y == idx)
continue;
const int arrVal = inputList[x][idx];
if (false == numCheck[arrVal])
{
numCheck[arrVal] = true;
}
}
if (true == numCheck[value])
return false;
return true;
}
bool CheckNemo(int x, int y, int value)
{
bool numCheck[10] = { false , };
int nemoX = 0;
int nemoY = 0;
if (0 <= x && 2 >= x)
nemoX = 0;
else if (3 <= x && 5 >= x)
nemoX = 3;
else
nemoX = 6;
if (0 <= y && 2 >= y)
nemoY = 0;
else if (3 <= y && 5 >= y)
nemoY = 3;
else
nemoY = 6;
for (int startX = nemoX; startX < nemoX + 3; startX++)
{
for (int startY = nemoY; startY < nemoY + 3; startY++)
{
if (x == startX && y == startY)
continue;
const int arrVal = inputList[startX][startY];
if (false == numCheck[arrVal])
numCheck[arrVal] = true;
}
}
if (true == numCheck[value])
return false;
return true;
}
'Coding Problem > 백준' 카테고리의 다른 글
[백준] 11047 - 동전 0 (0) | 2021.05.28 |
---|---|
[백준] 11399 - ATM (0) | 2021.05.28 |
[백준] 18870 - 좌표 압축 (0) | 2021.05.03 |
[백준] 2447 - 별 찍기 - 10 (0) | 2021.04.29 |
[백준] 11653 - 소인수분해 (0) | 2021.04.17 |