#include using namespace std; #define rep(i, a, b) for(int i = a; i < (b); ++i) #define trav(a, x) for(auto& a : x) #define all(x) x.begin(), x.end() #define sz(x) (int)(x).size() typedef long long ll; typedef pair pii; typedef pair pll; typedef vector vi; // The first region is random tree-shaped and covers all overlaps. // The other regions fill the remaining gaps so that all overlaps get covered. // Runs multiple times. // Same as random_spanning_trees1 but with more heuristics. const int MAXN = 200; bool overlap[MAXN][MAXN] = {0}; vector overlaps; int n,m,k; string abc = "ABC"; int DX[4] = {0,0,1,-1}; int DY[4] = {1,-1,0,0}; bool inbounds(int i, int j){ return i >= 0 && j >= 0 && i < n && j < m; } bool COVER[3][MAXN][MAXN] = {0}; void print_answer(){ rep(c1,0,3){ rep(c2,0,n){ rep(c3,0,m){ if(COVER[c1][c2][c3]){ cout << abc[c1]; } else{ cout << '.'; } }cout << "\n"; }cout << "\n"; } } int owners(int i, int j){ return COVER[0][i][j] + COVER[1][i][j] + COVER[2][i][j]; } void take(int i, int j, int to){ rep(c1,0,4){ int i2 = i + DX[c1]; int j2 = j + DY[c1]; if(inbounds(i2,j2) && overlap[i2][j2] && !COVER[to][i2][j2]){ COVER[to][i2][j2] = 1; take(i2,j2,to); } } } void connect(int i, int j, int to){ if(COVER[to][i][j])return; int i2 = -1; int j2 = -1; rep(d,1,n+m-1){ rep(c1,-d,d+1){ for(int sig = -1; sig <= 1; sig += 2){ int i3 = i + c1; int j3 = j + sig*(d-abs(c1)); if(inbounds(i3,j3) && COVER[to][i3][j3]){ i2 = i3; j2 = j3; } } if(i2 != -1)break; }if(i2 != -1)break; } if(i2 == -1)return; while(i != i2 ||j != j2){ COVER[to][i][j] = 1; take(i,j,to); int r = rand()%2; if(i == i2)r = 1; if(j == j2)r = 0; if(r == 0){ if(i > i2){i--;}else{i++;} } else{ if(j > j2){j--;}else{j++;} } } } void flood_fill(int i, int j, int to){ if(COVER[to][i][j] || (!overlap[i][j] && owners(i,j) > 0))return; COVER[to][i][j] = 1; rep(c1,0,4){ int i2 = i + DX[c1]; int j2 = j + DY[c1]; if(inbounds(i2,j2)){ flood_fill(i2,j2,to); } } } bool validate(){ // Let's assume each region is connected. rep(c1,0,n){ rep(c2,0,m){ if(overlap[c1][c2] && owners(c1,c2) < 2)return 0; if(!overlap[c1][c2] && owners(c1,c2) >= 2)return 0; } } return 1; } int any_neighbour(int i, int j){ rep(c1,0,4){ int i2 = i + DX[c1]; int j2 = j + DY[c1]; if(inbounds(i2,j2)){ rep(c2,0,3){ if(COVER[c2][i2][j2])return c2; } } } return -1; } void emergency_unblock(int to){ trav(p, overlaps){ int i = p.first; int j = p.second; if(COVER[to][i][j]){ int i3 = 0; int j3 = 0; bool bad = 1; rep(c1,0,4){ int i2 = i + DX[c1]; int j2 = j + DY[c1]; if(inbounds(i2,j2)){ if(COVER[to][i2][j2] && !overlap[i2][j2]){ i3 = i2; j3 = j2; } else{ bad = 0; } } } if(bad){ COVER[to][i3][j3] = 0; rep(c1,-1,2){ rep(c2,-1,2){ if((c1 != 0 || c2 != 0) && inbounds(i3+c1,j3+c2)){ COVER[to][i3+c1][j3+c2] = 1; } } } } } } } bool comp(pii p1, pii p2){ int d1 = abs(p1.first - overlaps[0].first) + abs(p1.second - overlaps[0].second); int d2 = abs(p1.first - overlaps[0].first) + abs(p1.second - overlaps[0].second); return d1 < d2; } int main() { cin >> n >> m; rep(c1,0,n){ string s; cin >> s; rep(c2,0,m){ if(s[c2] == '2'){ overlap[c1][c2] = 1; overlaps.push_back({c1,c2}); } } } k = sz(overlaps); if(k == 0){ if(n*m <= 2){ cout << "impossible\n"; return 0; } rep(c1,0,3){ rep(c2,0,n){ rep(c3,0,m){ int a = 0; if(c2 == 0 && c3 == 0)a = 1; if((c2 == 0 && c3 == 1) || (c2+c3 == 1 && m == 1))a = 2; if(c1 == a){ cout << abc[a]; } else{ cout << '.'; } } cout << "\n"; }cout << "\n"; }return 0; } while(1){ rep(c1,0,3){ rep(c2,0,n){ rep(c3,0,m){ COVER[c1][c2][c3] = 0; } } } random_shuffle(all(overlaps)); COVER[0][overlaps[0].first][overlaps[0].second] = 1; vector overlaps2; rep(c1,1,k){ overlaps2.push_back(overlaps[c1]); } sort(all(overlaps2), comp); rep(c1,0,k-1){ connect(overlaps2[c1].first, overlaps2[c1].second, 0); } emergency_unblock(0); rep(c1,1,3){ bool found = 0; rep(c2,0,n){ rep(c3,0,m){ if(overlap[c2][c3] && owners(c2,c3) < 2){ found = 1; flood_fill(c2,c3,c1); break; } } if(found)break; } if(!found)flood_fill(overlaps[0].first,overlaps[0].second,c1); } if(validate()){ rep(c1,0,n){ rep(c2,0,m){ if(owners(c1,c2) == 0){ int a = any_neighbour(c1,c2); if(a != -1){ flood_fill(c1,c2,a); } } } } print_answer(); return 0; } if(min(n,m) == 1)break; } cout << "impossible\n"; return 0; }