UVa 11846 Finding Seats Again

UVa 11846 Finding Seats Again
http://uva.onlinejudge.org/external/118/11846.html

問題概要

最大20*20の正方形のグリッドがあたえられる。
グリッドにはところどころに、1〜9までの数字が入っている。
各数字はその数字が含まれるべき長方形の面積を表している。
すべての数字の和は正方形の面積である。
正方形を数字の数分の長方形に分割せよ。
ただし、長方形同士重なり合うことはない。
答えは必ず見つかる。

解法

探索。
答えは必ずみつかることから、
左上から全部見ていって、
未確定のマスがあれば、そのマスを左上とした長方形を適当に作る。
面積が最大9なのでそこまで候補がおおくないし、
答えは必ず見つかることからわりと早く終わる。

#include<cstdio>
#include<cctype>

#define REP(i, b, n) for(int i = b; i < n; i++)
#define rep(i, n) REP(i, 0, n)

using namespace std;

const int N = 20;

char t[N][N], ans[N][N];
int n;

bool dfs(char c, int pos){
  while(pos != n * n && ans[pos/n][pos%n] != '.')pos++;
  if(pos == n*n)return true;
  int bx = pos%n, by = pos/n;
  REP(h, by, n){
    REP(w, bx, n){
      int cnt = 0, area = (h - by + 1) * (w - bx + 1);
      if( area > 9)break;
      if(ans[h][w] != '.')break;
      int now = -1;
      bool out = false;
      REP(y, by, h+1){
        REP(x, bx, w+1){
          if(isdigit(t[y][x])){
            cnt++;
            now = (t[y][x] - '0');
          }
          if(ans[y][x] != '.'){
            out = true;
            break;
          }
        }
        if(out || cnt > 1 || (now != -1 && now != area))break;
      }
      if(cnt > 1 || (now != -1 && (area > now || now % (h-by+1) != 0 ) ) || out)break;
      if(cnt == 0 || now > area)continue;
      REP(y, by, h+1){
        REP(x, bx, w+1){
          ans[y][x] = c;
        }
      }
      if(dfs(c+1, pos+(w-bx+1)))return true;
      REP(y, by, h+1){
        REP(x, bx, w+1){
          ans[y][x] = '.';
        }
      }
    }
  }
  return false;
}

int main(){
  int tmp ;
  while(scanf("%d%d", &n, &tmp)){
    if( n == 0 && tmp == 0)break;
    rep(i, n){
      rep(j, n){
        scanf(" %c ",&t[i][j]);
        ans[i][j] = '.';
      }
    }
    dfs('A', 0);
    rep(i, n){
      rep(j, n){
        putchar(ans[i][j]);
      }
      putchar('\n');
    }
  }
  return 0;
}