import java.io.*; import java.util.*; public class MedianFilter { private static final Scanner cin = new Scanner(System.in); public static void main(String[] args) { for(int iCase = 1; ; iCase++) { TestCase testCase = TestCase.scan(cin); if(testCase == null) { break; } int n = testCase.solve(); if(n == -1) { System.out.println("Case " + iCase + ": Impossible"); } else { System.out.println("Case " + iCase + ": " + n); } } } private static class TestCase { private final boolean[][] bmp; private final int cx; private final int cy; private TestCase(int cx, int cy) { this.bmp = new boolean[cx][cy]; this.cx = cx; this.cy = cy; } public static TestCase scan(Scanner in) { int cx = in.nextInt(); int cy = in.nextInt(); if(cx == 0 && cy == 0) return null; TestCase rv = new TestCase(cx, cy); for(int y = 0; y < cy; y++) { String s = in.next(); for(int x = 0; x < cx; x++) { rv.bmp[x][y] = (s.charAt(x) == '#'); } } return rv; } private void reduce(int q, int[] out) { int n = 0; if((q & 1) != 0) { n++; } if((q & 2) != 0) { n++; } for(int x = cx - 1; x >= 0; x--) { if((q & 4) != 0) { n++; } out[x] += n; if((q & 1) != 0) { n--; } q >>= 1; } } private void dfs(int x, int y, int q, int n, int[] pre, MinMax mm, Map out) { if(x == cx) { if(!out.containsKey(q)) { out.put(q, new MinMax(cx * cy, 0)); } out.get(q).min = Math.min(out.get(q).min, mm.min + n); out.get(q).max = Math.max(out.get(q).max, mm.max + n); return; } int m = Integer.bitCount(q & 3); if(x == cx - 1) { int j = (q & 1); if(bmp[x][y] == (pre[x] + m >= 5 - j)) dfs(x + 1, y, (q << 1) | j, n + 0, pre, mm, out); } else { if(bmp[x][y] == (pre[x] + m >= 5 - 0)) dfs(x + 1, y, (q << 1) | 0, n + 0, pre, mm, out); if(bmp[x][y] == (pre[x] + m >= 5 - 1)) dfs(x + 1, y, (q << 1) | 1, n + 1, pre, mm, out); } } private int solve() { Map> m1 = new HashMap>(); Map> m2 = new HashMap>(); Map> mx; // prepare for(int i = 0; i < (1 << cx); i++) { int n = Integer.bitCount(i); int q = ((i << 2) & (2 << cx)) | (i << 1) | (i & 1); m1.put(q, new HashMap()); m1.get(q).put(q, new MinMax(n, n)); } int[] pre = new int[cx]; for(int y = 0; y < cy - 1; y++) { for(int q1 : m1.keySet()) { for(int q2 : m1.get(q1).keySet()) { if(!m2.containsKey(q2)) m2.put(q2, new HashMap()); Arrays.fill(pre, 0); reduce(q1, pre); reduce(q2, pre); dfs(0, y, 0, 0, pre, m1.get(q1).get(q2), m2.get(q2)); dfs(0, y, 3, 1, pre, m1.get(q1).get(q2), m2.get(q2)); } } mx = m1; m1 = m2; m2 = mx; m2.clear(); } MinMax mm = new MinMax(cx * cy, 0); for(int q1 : m1.keySet()) { for(int q2 : m1.get(q1).keySet()) { Arrays.fill(pre, 0); reduce(q1, pre); reduce(q2, pre); reduce(q2, pre); boolean okay = true; for(int x = 0; x < cx; x++) { if(bmp[x][cy - 1] != (pre[x] >= 5)) { okay = false; break; } } if(okay) { mm.min = Math.min(mm.min, m1.get(q1).get(q2).min); mm.max = Math.max(mm.max, m1.get(q1).get(q2).max); } } } return Math.max(mm.max - mm.min, -1); } } private static class MinMax { public int min; public int max; public MinMax(int min, int max) { this.min = min; this.max = max; } } }