문제풀이
이번에 입력으로 주어진 데이터들은 모두 'Trial and Error' 를 거치지 않고서도 풀 수 있는 데이터였습니다. (라고 책에 나와있습니다) 그런데 생각하고 있는 알고리즘을 모두 구현하기가 쉽지 않아서 결국은 Trial-and-Error로 풀게 되었지요 :<
하지만 모든 경우에 대해서 무작정 Back-Tracking 기법을 사용하는것보다는 확실히 정해진 일부 칸들을 먼저 구합니다. 예를 들어 두 칸이 비어있는데 합이 16인 경우라면 (7, 9) 이외의 숫자는 해당 칸에 사용할 수가 없는 식으로요. 이런식으로 어떤 칸에 사용할 수 없는 숫자들을 테이블로 미리 구해둔다면 꽤나 많은 경우의 수가 단축됩니다.
저는 우선 이정도의 처리만 했는데요, 좀 더 다양한 알고리즘이 존재하니 도전해 보시면 좋을 듯 합니다 :D
소스코드
~~~ cpp
#include
#include
using namespace std;
struct elem
{
int x, y, rc, sum;
};
struct BACKUP_STATE
{
int _allow[30][30];
vector > _table;
};
bool found;
int allow[30][30];
vector allcase[46][10];
int bit[46][10];
vector > state[30][30];
vector > table;
vector data;
vector conn[30][30]; // 현재 좌표에 영향을 미치는 data의 index
vector btable;
int dx[4] = {0, 1, -1, 0};
int dy[4] = {1, 0, 0, -1};
int N, M;
FILE *in = stdin;
void backup()
{
BACKUP_STATE tmp;
for (int i = 0; i <= N; ++i)
for (int j = 0; j <= N; ++j)
tmp._allow[i][j] = allow[i][j];
tmp._table = table;
btable.push_back(tmp);
}
void load()
{
BACKUP_STATE tmp = btable[btable.size() - 1];
for (int i = 0; i <= N; ++i)
for (int j = 0; j <= N; ++j)
allow[i][j] = tmp._allow[i][j];
table = tmp._table;
}
void recover()
{
BACKUP_STATE tmp = btable[btable.size() - 1];
for (int i = 0; i <= N; ++i)
for (int j = 0; j <= N; ++j)
allow[i][j] = tmp._allow[i][j];
table = tmp._table;
btable.pop_back();
}
void init()
{
for (int i = 1; i < (1 << 9); ++i)
{
vector tmp;
int sum = 0;
int cn = 0;
for (int j = 0; j < 9; ++j)
if (i & (1 << j))
{
sum += (j + 1);
cn++;
}
allcase[sum][cn].push_back(i);
bit[sum][cn] |= i;
}
}
void input()
{
fscanf(in, "%d", &N);
table.assign(N + 1, vector (N + 1, -1));
memset(allow, 0, sizeof(allow));
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
{
fscanf(in, "%d", &table[i][j]);
if (table[i][j] == 1) allow[i][j] = (1 << 9) - 1;
table[i][j]--;
conn[i][j].clear();
}
fscanf(in, "%d", &M);
data.resize(M);
for (int i = 0; i < M; ++i)
{
fscanf(in, "%d %d %d %d", &data[i].x, &data[i].y, &data[i].rc, &data[i].sum);
data[i].x--;
data[i].y--;
}
}
int GetCount(int x, int y, int rc, int &must, int &mustnot)
{
int ret = 0;
for (;;)
{
x += dx[rc];
y += dy[rc];
if (table[x][y] != -1)
{
ret++;
if (table[x][y] != 0)
{
must |= (1 << (table[x][y] - 1));
mustnot |= (1 << (table[x][y] - 1));
}
}
else
{
break;
}
}
return ret;
}
int go(int sum, int remain, int must, int mustnot)
{
int ret = bit[sum][remain] - mustnot;
int bitmask = 0;
for (int i = 0; i < allcase[sum][remain].size(); ++i)
{
if ((must & allcase[sum][remain][i]) == must)
{
bitmask |= allcase[sum][remain][i];
}
}
return ret & bitmask;
}
void greedy1()
{
for (int i = 0; i < M; ++i)
{
int x = data[i].x, y = data[i].y;
int rc = data[i].rc, sum = data[i].sum;
int must = 0, mustnot = 0;
int gc = GetCount(x, y, rc, must, mustnot);
for (;;)
{
x += dx[rc], y += dy[rc];
if (table[x][y] == -1) break;
allow[x][y] &= go(sum, gc, must, mustnot);
}
}
}
bool isFinish()
{
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
if (table[i][j] == 0) return false;
return true;
}
bool find(int x, int y, int v)
{
v++;
for (int i = 0; i < 4; ++i)
{
int xx = x, yy = y;
for (;;)
{
xx += dx[i], yy += dy[i];
if (table[xx][yy] == -1) break;
if (table[xx][yy] == v) return true;
}
}
return false;
}
bool set()
{
bool ret = false;
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < N; ++j)
{
if (table[i][j] == 0)
{
if ((allow[i][j] & (allow[i][j] - 1)) == 0)
{
for (int k = 0; k < 9; ++k)
if (allow[i][j] & (1 << k))
{
if (!find(i, j, k))
{
table[i][j] = k + 1;
ret = true;
}
}
}
}
}
}
return ret;
}
void backtr(int x, int y)
{
if (found) return;
while (!isFinish())
{
greedy1();
if (!set()) break;
}
if (isFinish())
{
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
printf("%d", max(table[i][j], 0));
if (j != N - 1) printf(" ");
}
printf("\n");
}
found = true;
return;
}
backup();
for (;;)
{
y++;
if (y == N) { y = 0, x++; }
if (table[x][y] == 0) break;
}
for (int i = 0; i < 9; ++i)
{
if ((allow[x][y] & (1 << i)) != 0)
{
table[x][y] = i + 1;
backtr(x, y);
table[x][y] = 0;
load();
}
}
recover();
}
int main()
{
init();
int T;
fscanf(in, "%d", &T);
while (T--)
{
btable.clear();
input();
found = false;
backtr(0, 0);
}
}
<div>[이 글은 과거 홈페이지에서 이전된 글입니다. <a href="http://algospot.andromeda-express.com/zbxe/editorial/50134">원문보기</a>]</div>
16년 전
0개의 댓글이 있습니다.
정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면
온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야
합니다. 현재 문제를 푸셨습니다.
astein
#include > _table; allcase[46][10]; > state[30][30]; > table; data; conn[30][30]; // 현재 좌표에 영향을 미치는 data의 index btable; tmp; (N + 1, -1));
#include
using namespace std;
struct elem
{
int x, y, rc, sum;
};
struct BACKUP_STATE
{
int _allow[30][30];
vector
};
bool found;
int allow[30][30];
vector
int bit[46][10];
vector
vector
vector
vector
vector
int dx[4] = {0, 1, -1, 0};
int dy[4] = {1, 0, 0, -1};
int N, M;
FILE *in = stdin;
void backup()
{
BACKUP_STATE tmp;
for (int i = 0; i <= N; ++i)
for (int j = 0; j <= N; ++j)
tmp._allow[i][j] = allow[i][j];
tmp._table = table;
btable.push_back(tmp);
}
void load()
{
BACKUP_STATE tmp = btable[btable.size() - 1];
for (int i = 0; i <= N; ++i)
for (int j = 0; j <= N; ++j)
allow[i][j] = tmp._allow[i][j];
table = tmp._table;
}
void recover()
{
BACKUP_STATE tmp = btable[btable.size() - 1];
for (int i = 0; i <= N; ++i)
for (int j = 0; j <= N; ++j)
allow[i][j] = tmp._allow[i][j];
table = tmp._table;
btable.pop_back();
}
void init()
{
for (int i = 1; i < (1 << 9); ++i)
{
vector
int sum = 0;
int cn = 0;
for (int j = 0; j < 9; ++j)
if (i & (1 << j))
{
sum += (j + 1);
cn++;
}
allcase[sum][cn].push_back(i);
bit[sum][cn] |= i;
}
}
void input()
{
fscanf(in, "%d", &N);
table.assign(N + 1, vector
memset(allow, 0, sizeof(allow));
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
{
fscanf(in, "%d", &table[i][j]);
if (table[i][j] == 1) allow[i][j] = (1 << 9) - 1;
table[i][j]--;
conn[i][j].clear();
}
fscanf(in, "%d", &M);
data.resize(M);
for (int i = 0; i < M; ++i)
{
fscanf(in, "%d %d %d %d", &data[i].x, &data[i].y, &data[i].rc, &data[i].sum);
data[i].x--;
data[i].y--;
}
}
int GetCount(int x, int y, int rc, int &must, int &mustnot)
{
int ret = 0;
for (;;)
{
x += dx[rc];
y += dy[rc];
if (table[x][y] != -1)
{
ret++;
if (table[x][y] != 0)
{
must |= (1 << (table[x][y] - 1));
mustnot |= (1 << (table[x][y] - 1));
}
}
else
{
break;
}
}
return ret;
}
int go(int sum, int remain, int must, int mustnot)
{
int ret = bit[sum][remain] - mustnot;
int bitmask = 0;
for (int i = 0; i < allcase[sum][remain].size(); ++i)
{
if ((must & allcase[sum][remain][i]) == must)
{
bitmask |= allcase[sum][remain][i];
}
}
return ret & bitmask;
}
void greedy1()
{
for (int i = 0; i < M; ++i)
{
int x = data[i].x, y = data[i].y;
int rc = data[i].rc, sum = data[i].sum;
int must = 0, mustnot = 0;
int gc = GetCount(x, y, rc, must, mustnot);
for (;;)
{
x += dx[rc], y += dy[rc];
if (table[x][y] == -1) break;
allow[x][y] &= go(sum, gc, must, mustnot);
}
}
}
bool isFinish()
{
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
if (table[i][j] == 0) return false;
return true;
}
bool find(int x, int y, int v)
{
v++;
for (int i = 0; i < 4; ++i)
{
int xx = x, yy = y;
for (;;)
{
xx += dx[i], yy += dy[i];
if (table[xx][yy] == -1) break;
if (table[xx][yy] == v) return true;
}
}
return false;
}
bool set()
{
bool ret = false;
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < N; ++j)
{
if (table[i][j] == 0)
{
if ((allow[i][j] & (allow[i][j] - 1)) == 0)
{
for (int k = 0; k < 9; ++k)
if (allow[i][j] & (1 << k))
{
if (!find(i, j, k))
{
table[i][j] = k + 1;
ret = true;
}
}
}
}
}
}
return ret;
}
void backtr(int x, int y)
{
if (found) return;
while (!isFinish())
{
greedy1();
if (!set()) break;
}
if (isFinish())
{
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
printf("%d", max(table[i][j], 0));
if (j != N - 1) printf(" ");
}
printf("\n");
}
found = true;
return;
}
backup();
for (;;)
{
y++;
if (y == N) { y = 0, x++; }
if (table[x][y] == 0) break;
}
for (int i = 0; i < 9; ++i)
{
if ((allow[x][y] & (1 << i)) != 0)
{
table[x][y] = i + 1;
backtr(x, y);
table[x][y] = 0;
load();
}
}
recover();
}
int main()
{
init();
int T;
fscanf(in, "%d", &T);
while (T--)
{
btable.clear();
input();
found = false;
backtr(0, 0);
}
}
16년 전