4997 - ABCD Tiles
4997 - ABCD Tiles
Asia - Kuala Lumpur - 2010/2011
http://acm.uva.es/archive/nuevoportal/data/problem.php?p=4997
- 問題概要
十字型のパネルを隙間無く埋めれるか。
3種類のパネルがあり、8方向に同じ種類のタイルは接してはいけない。
辞書順最小の埋め方を答えよ。
埋めれないなら埋めれないと答えよ。
- 解法
埋め方は一意に定まる。
塗り方は貪欲で一番最初に見つかったものが答え。
貪欲でやると塗れない、けど、塗り方を少し変えると塗れる場合もあることに注意。
塗るとき、ピースをグラフに落として、
グラフを彩色していく感じでやると書きやすく感じた。
(僕が考えたわけではないですが。
書きやすい実装の勉強になった。
- ソース
#include<iostream> #include<string> #include<algorithm> #include<cstdio> #define REP(i,b,n) for(int i=b;i<(int)n;i++) #define rep(i,n) REP(i,0,n) using namespace std; const int dx[] = {0, 1, 1, 1, 0, -1, -1, -1}; const int dy[] = {-1, -1, 0, 1, 1, 1, 0, -1}; const int px[] = {-1, 0, 1, 0}; const int py[] = {1, 1, 1, 2}; const int N = 15; const string IMP = " Not Possible!"; const int E = 50; int t[N][N], n, ID; bool edge[E][E]; int C[E]; string ans; bool invalid(int y, int x){ if(x < 0 || y < 0 || x >= n || y >= n)return true; return false; } void input(){ rep(i, n){ rep(j, n){ char c; cin >> c; if(c == 'A')t[i][j] = 0; else t[i][j] = -1; } } rep(i, E){ rep(j, E){ edge[i][j] = false;; } } ID = 0; ans = ""; rep(i, E)C[i] = -1; } bool canPut(int y, int x, int &ID){ rep(i, 4){ int ny = y + py[i]; int nx = x + px[i]; if(invalid(ny, nx) || t[ny][nx] >= 0)return false; } rep(i, 4){ int ny = y + py[i]; int nx = x + px[i]; t[ny][nx] = ID; } t[y][x] = ID; ID++; return true; } bool putID(){ ID = 1; rep(i, n){ rep(j, n){ if(t[i][j] >= 0)continue; if(canPut(i, j, ID))continue; return false; } } ID--; return true; } void makeGraph(){ rep(i, n){ rep(j, n){ if(t[i][j] < 1)continue; rep(d, 8){ int ny = dy[d] + i; int nx = dx[d] + j; if(invalid(ny, nx))continue; if(t[ny][nx] == t[i][j])continue; if(t[ny][nx] < 1)continue; edge[t[i][j]-1][t[ny][nx]-1] = edge[t[ny][nx]-1][t[i][j]-1] = true; } } } } void make_ans(){ rep(i, ID){ ans += 'B' + C[i]; } } bool solve(int pos){ if(pos == ID){ make_ans(); return true; } rep(c, 3){ bool flag = false; rep(i, pos){ if(!edge[pos][i])continue; if(C[i] < 0)continue; if(c == C[i]){ flag = true; break; } } if(flag)continue; C[pos] = c; if(solve(pos+1))return true; C[pos] = -1; } return false; } void output(){ printf("\n"); rep(i, n){ rep(j, n){ if(t[i][j] == 0){ printf("A"); } else { printf("%c", ans[t[i][j]-1]); } } printf("\n"); } } int main(){ int T; cin >> T; rep(tc, T){ cin >> n; printf("Case %d:",tc+1); input(); if(!putID()){ printf("%s\n", IMP.c_str()); continue; } makeGraph(); if(solve(0))output(); else printf("%s\n", IMP.c_str()); } return 0; }