2114-Median Filter
問題概要
黒と白のみから構成された画像にメディアンフィルターを掛けたものが与えられる.
元の画像として考えられるもののうち,黒の個数が最大のものと最小のものの差を答えろ.
解法
前(W*2+2)マスを保持するBitDP.
計算量は W * H * 2^((W+1)*2) ぐらいになる.
DP配列の初期化をmemsetで行なうとTLEする.
実装(C++)
#include <cstring> #include <algorithm> #include <vector> #include <iostream> #include <boost/format.hpp> using namespace std; #define REP(i,x) for(int i=0;i<(int)(x);i++) #define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++) #define RREP(i,x) for(int i=(x);i>=0;i--) #define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();i++) int dx[9]={-1,0,1,0,-1,-1,1,1,0},dy[9]={0,-1,0,1,1,-1,1,-1,0}; int W,H; int MAP[8][8]; int ROW[8]; typedef char DP_TYPE; DP_TYPE DP_MAX[1<<18][8][8]; DP_TYPE DP_MIN[1<<18][8][8]; int mask; int get_data(int back,int x,int y,int sx,int sy,int now){ if(sy<0)sy=0; if(sx<0)sx=0; if(sx>=W)sx=W-1; if(sy>=H)sy=H-1; int cnt=(y-sy)*W+x-sx-1; if(cnt>=0&&cnt<2*W+2){ return (back>>cnt)&1; } if(cnt==-1)return now; } //周辺の黒の個数を数える int count(int back,int x,int y,int sx,int sy,int now){ int res=0; for(int i=0;i<9;i++){ res+=get_data(back,x,y,sx+dx[i],sy+dy[i],now); } return res; } DP_TYPE solve(int back,int x,int y){ if(y==H)return 0; DP_TYPE &ret=DP_MIN[back][x][y]; int nx=x+1,ny=y; if(nx>=W){ ny+=1;nx=0; } if(ret==0x7F){ //このマスに置くか置かないか ret=0x7E; if(y==0&&H!=1){ ret=min<DP_TYPE>(ret,solve((((back)<<1)|0)&mask,nx,ny)); if(solve((((back)<<1)|1)&mask,nx,ny)<0x7E)ret=min<DP_TYPE>(ret,solve((((back)<<1)|1)&mask,nx,ny)+1); }else if(y<H-1||H==1){ if(x==0&&W!=1){ ret=min<DP_TYPE>(ret,solve(((back<<1)|0)&mask,nx,ny)); if(solve(((back<<1)|1)&mask,nx,ny)<0x7E)ret=min<DP_TYPE>(ret,solve(((back<<1)|1)&mask,nx,ny)+1); }else if(x<W-1||W==1){ int sx=x-1; int sy=y-1; if(sx<0)sx=0;if(sy<0)sy=0; if(MAP[sx][sy]==count(back,x,y,sx,sy,0)/5){ ret=min<DP_TYPE>(ret,solve(((back<<1)|0)&mask,nx,ny)); } if(MAP[sx][sy]==count(back,x,y,sx,sy,1)/5){ if(solve(((back<<1)|1)&mask,nx,ny)<0x7E)ret=min<DP_TYPE>(ret,solve(((back<<1)|1)&mask,nx,ny)+1); } }else{ int sx=x-1; int sy=y-1; if(sx<0)sx=0;if(sy<0)sy=0; if(MAP[sx][sy]==count(back,x,y,sx,sy,0)/5&&MAP[sx+1][sy]==count(back,x,y,sx+1,sy,0)/5){ ret=min<DP_TYPE>(ret,solve(((back<<1)|0)&mask,nx,ny)); } if(MAP[sx][sy]==count(back,x,y,sx,sy,1)/5&&MAP[sx+1][sy]==count(back,x,y,sx+1,sy,1)/5){ if(solve(((back<<1)|1)&mask,nx,ny)<0x7E)ret=min<DP_TYPE>(ret,solve(((back<<1)|1)&mask,nx,ny)+1); } } }else{ if(x==0&&W!=1){ ret=min<DP_TYPE>(ret,solve(((back<<1)|0)&mask,nx,ny)); if(solve(((back<<1)|1)&mask,nx,ny)<0x7E)ret=min<DP_TYPE>(ret,solve(((back<<1)|1)&mask,nx,ny)+1); }else if(x<W-1||W==1){ int sx=x-1; int sy=y-1; if(sx<0)sx=0;if(sy<0)sy=0; if(MAP[sx][sy]==count(back,x,y,sx,sy,0)/5&&MAP[sx][sy+1]==count(back,x,y,sx,sy+1,0)/5){ ret=min<DP_TYPE>(ret,solve(((back<<1)|0)&mask,nx,ny)); } if(MAP[sx][sy]==count(back,x,y,sx,sy,1)/5&&MAP[sx][sy+1]==count(back,x,y,sx,sy+1,1)/5){ if(solve(((back<<1)|1)&mask,nx,ny)<0x7E)ret=min<DP_TYPE>(ret,solve(((back<<1)|1)&mask,nx,ny)+1); } }else{ int sx=x-1; int sy=y-1; if(sx<0)sx=0;if(sy<0)sy=0; if(MAP[sx][sy]==count(back,x,y,sx,sy,0)/5&&MAP[sx][sy+1]==count(back,x,y,sx,sy+1,0)/5&&MAP[sx+1][sy+1]==count(back,x,y,sx+1,sy+1,0)/5&&MAP[sx+1][sy]==count(back,x,y,sx+1,sy,0)/5){ ret=min<DP_TYPE>(ret,solve(((back<<1)|0)&mask,nx,ny)); } if(MAP[sx][sy]==count(back,x,y,sx,sy,1)/5&&MAP[sx][sy+1]==count(back,x,y,sx,sy+1,1)/5&&MAP[sx+1][sy+1]==count(back,x,y,sx+1,sy+1,1)/5&&MAP[sx+1][sy]==count(back,x,y,sx+1,sy,1)/5){ if(solve(((back<<1)|1)&mask,nx,ny)<0x7E)ret=min<DP_TYPE>(ret,solve(((back<<1)|1)&mask,nx,ny)+1); } } } //cout<<boost::format("%d,%d,%d:%d\n")%back%x%y%(int)ret; } return ret; } DP_TYPE solve2(int back,int x,int y){ if(y==H)return 0; DP_TYPE &ret=DP_MAX[back][x][y]; int nx=x+1,ny=y; if(nx>=W){ ny+=1;nx=0; } if(ret==-1){ //このマスに置くか置かないか ret=-2; if(y==0&&H!=1){ ret=max<DP_TYPE>(ret,solve2((((back)<<1)|0)&mask,nx,ny)); if(solve2((((back)<<1)|1)&mask,nx,ny)>=0)ret=max<DP_TYPE>(ret,solve2((((back)<<1)|1)&mask,nx,ny)+1); }else if(y<H-1||H==1){ if(x==0&&W!=1){ ret=max<DP_TYPE>(ret,solve2(((back<<1)|0)&mask,nx,ny)); if(solve2(((back<<1)|1)&mask,nx,ny)>=0)ret=max<DP_TYPE>(ret,solve2(((back<<1)|1)&mask,nx,ny)+1); }else if(x<W-1||W==1){ int sx=x-1; int sy=y-1; if(sx<0)sx=0;if(sy<0)sy=0; if(MAP[sx][sy]==count(back,x,y,sx,sy,0)/5){ ret=max<DP_TYPE>(ret,solve2(((back<<1)|0)&mask,nx,ny)); } if(MAP[sx][sy]==count(back,x,y,sx,sy,1)/5){ if(solve2(((back<<1)|1)&mask,nx,ny)>=0)ret=max<DP_TYPE>(ret,solve2(((back<<1)|1)&mask,nx,ny)+1); } }else{ int sx=x-1; int sy=y-1; if(sx<0)sx=0;if(sy<0)sy=0; if(MAP[sx][sy]==count(back,x,y,sx,sy,0)/5&&MAP[sx+1][sy]==count(back,x,y,sx+1,sy,0)/5){ ret=max<DP_TYPE>(ret,solve2(((back<<1)|0)&mask,nx,ny)); } if(MAP[sx][sy]==count(back,x,y,sx,sy,1)/5&&MAP[sx+1][sy]==count(back,x,y,sx+1,sy,1)/5){ if(solve2(((back<<1)|1)&mask,nx,ny)>=0)ret=max<DP_TYPE>(ret,solve2(((back<<1)|1)&mask,nx,ny)+1); } } }else{ if(x==0&&W!=1){ ret=max<DP_TYPE>(ret,solve2(((back<<1)|0)&mask,nx,ny)); if(solve2(((back<<1)|1)&mask,nx,ny)>=0)ret=max<DP_TYPE>(ret,solve2(((back<<1)|1)&mask,nx,ny)+1); }else if(x<W-1||W==1){ int sx=x-1; int sy=y-1; if(sx<0)sx=0;if(sy<0)sy=0; if(MAP[sx][sy]==count(back,x,y,sx,sy,0)/5&&MAP[sx][sy+1]==count(back,x,y,sx,sy+1,0)/5){ ret=max<DP_TYPE>(ret,solve2(((back<<1)|0)&mask,nx,ny)); } if(MAP[sx][sy]==count(back,x,y,sx,sy,1)/5&&MAP[sx][sy+1]==count(back,x,y,sx,sy+1,1)/5){ if(solve2(((back<<1)|1)&mask,nx,ny)>=0)ret=max<DP_TYPE>(ret,solve2(((back<<1)|1)&mask,nx,ny)+1); } }else{ int sx=x-1; int sy=y-1; if(sx<0)sx=0;if(sy<0)sy=0; if(MAP[sx][sy]==count(back,x,y,sx,sy,0)/5&&MAP[sx][sy+1]==count(back,x,y,sx,sy+1,0)/5&&MAP[sx+1][sy+1]==count(back,x,y,sx+1,sy+1,0)/5&&MAP[sx+1][sy]==count(back,x,y,sx+1,sy,0)/5){ ret=max<DP_TYPE>(ret,solve2(((back<<1)|0)&mask,nx,ny)); } if(MAP[sx][sy]==count(back,x,y,sx,sy,1)/5&&MAP[sx][sy+1]==count(back,x,y,sx,sy+1,1)/5&&MAP[sx+1][sy+1]==count(back,x,y,sx+1,sy+1,1)/5&&MAP[sx+1][sy]==count(back,x,y,sx+1,sy,1)/5){ if(solve2(((back<<1)|1)&mask,nx,ny)>=0)ret=max<DP_TYPE>(ret,solve2(((back<<1)|1)&mask,nx,ny)+1); } } } } return ret; } bool input(){ cin>>W>>H; if(W==0&&H==0)return false; for(int i=0;i<H;i++){ ROW[i]=0; string in; cin>>in; for(int j=0;j<W;j++){ MAP[j][i]=(in[j]=='#'); if(in[j]=='#')ROW[i]|=1<<j; } } return true; } void initdp(){ for(int i=0;i<(1<<(W*2+2));i++){ for(int j=0;j<W;j++){ for(int k=0;k<H;k++){ DP_MAX[i][j][k]=0xFF; DP_MIN[i][j][k]=0x7F; } } } } int t=0; int main(){ while(input()){ //DP配列の初期化 initdp(); mask=(1LL<<((W+1)*2))-1; int rm=solve2(0,0,0); if(rm<0||solve(0,0,0)>=0x7E){ cout<<boost::format("Case %d: Impossible")%++t<<endl; continue; } cout<<boost::format("Case %d: %d")%++t%(int)(rm-solve(0,0,0))<<endl; } return 0; }