るくすの日記 ~ Out_Of_Range ~

主にプログラミング関係

AOJ 0131 Doctor's Strange Particles

問題文→ AIZU ONLINE JUDGE

「あるマスを選んでそこの数字を反転(1 <-> 0)させる。 この時そのマスの上下左右も反転する。 すべてを0にするために必要な反転箇所を求めよ」 という問題。

普通に考えたら O(2^100)とかで無理。 

そこで一番上の行の反転の仕方を一意に決める。するとそこから下の行も一意に決まるので O(10*10*2^10)になって間に合う。

2^nのdfsにビットを使ってみた。すごい便利ー^ ^

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#include<cmath>
#include<map>
#include<cstdlib>
#include<deque>
#include<queue>
#include<climits>
#include<cstring>
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)
using namespace std;
typedef vector<string> VS;
typedef vector<int> VI;
const int dx[5]={-1,0,0,0,1};
const int dy[5]={0,-1,0,1,0};
int stage[10][10];
int cnt[10][10];
int Color(int x,int y){
  int tmp=stage[x][y];
  REP(i,5){
    int nx=x+dx[i];
    int ny=y+dy[i];
    if(nx>=10 || ny>=10 || nx<0 || ny<0) continue;
    tmp+=cnt[nx][ny];
  }
  return tmp%2;
}
int solve(){
  for(int y=1;y<10;y++)
    for(int x=0;x<10;x++)
      if(Color(y-1,x)) cnt[y][x]=1;
  REP(i,10){ if(Color(9,i)) return -1;}
  int ret=0;
  REP(y,10) REP(x,10) ret+=cnt[y][x];
  return ret;
}
int ans[10][10];
void bit_dfs(){
  int res=-1;
  for(int i=0;i<1<<10;i++){//部分集合
    memset(cnt,0,sizeof(cnt));
    for(int j=0;j<10;j++) cnt[0][9-j]=i>>j&1;//集合切り出し
    int t=solve();
    if(t>=0 && (res<0 || res>t)){
      res=t;
      memcpy(ans,cnt,sizeof(cnt));
    }
  }
}     
int main(){
  int n; cin>>n;
  REP(i,n){
    memset(ans,0,sizeof(ans));
    memset(cnt,0,sizeof(cnt));
    memset(stage,0,sizeof(stage));
    REP(x,10) REP(y,10) cin>>stage[x][y];
    bit_dfs();
    REP(y,10){
      REP(x,10){
	cout<<ans[y][x];
	if(x<9) cout<<" ";
	else cout<<endl;
      }
    }
  }
}