AOJ : 0131 - Doctor's Strange Particles

問題概要

http://rose.u-aizu.ac.jp/onlinejudge/ProblemSet/description.jsp?id=0131
日本語の問題文なので省略.

アルゴリズム

一番上の行の粒子の通し方を再帰で決定します.(2^10)
二行目以降 [i][j] の通し方は,

  • すぐ上の行([i-1][j])が点灯しているなら通す
  • 点灯していないなら通さない

と, 必ず一通りに決定づけることができます.
これを10行目まで行って, 全て消灯できたら, その通し方が答えです.

プログラム

int t[10][10],s[10][10],ans[10][10];
int dx[] = {0,-1,0,1,0};
int dy[] = {-1,0,0,0,1};

bool check(int *used){
  memset(ans,0,sizeof(ans));
  memcpy(s,t,sizeof(t));

  for(int i=0;i<10;i++){
    ans[0][i] = used[i];
    if(used[i]){
      for(int j=0;j<5;j++){
        int nx = i + dx[j];
        int ny = dy[j];

        if(nx>=0 && 10>nx && ny>=0 && 10>ny){
          s[ny][nx] = !s[ny][nx];
        }
      }
    }
  }

  for(int i=1;i<10;i++){
    for(int j=0;j<10;j++){
      if(s[i-1][j]){ //上が1ならば必ず光が必要
        ans[i][j] = 1;
        for(int k=0;k<5;k++){
          int nx = j + dx[k];
          int ny = i + dy[k];

          if(nx>=0 && 10>nx && ny>=0 && 10>ny){
            s[ny][nx] = !s[ny][nx];
          }
        }
      }
    }
  }

  for(int i=0;i<10;i++){
    for(int j=0;j<10;j++){
      if(s[i][j]) return false;
    }
  }
  return true;
}

bool solve(int idx,int *used){
  if(idx == 10){
    if(check(used)){
      return true;
    }
    return false;
  }

  if(solve(idx+1,used)) return true;
  used[idx] = 1;
  if(solve(idx+1,used)) return true;
  used[idx] = 0;

  return false;
}

int main(void){
  int n;
  cin>>n;

  while(n--){
    for(int i=0;i<10;i++){
      for(int j=0;j<10;j++){
        cin>>t[i][j];
      }
    }

    int used[10];
    memset(used,0,sizeof(used));
    solve(0,used);

    for(int i=0;i<10;i++){
      for(int j=0;j<9;j++){
        cout<<ans[i][j]<<" ";
      }
      cout<<ans[i][9]<<endl;
    }
  }

  return 0;
}