POJ 3600 Subimage Recognition
問題
r行c列の'0','1'の行列AとR行C列の'0','1'の行列Bが与えられる。
Bの一部の行と、一部の列を削って、Aを作ることはできるか答えよ。
制約条件
r≦R≦20
c≦C≦20
方針
枝刈り+深さ優先探索
Bのi列に対して、Aのj列を部分文字列として含むかをok[i][j]として計算しておく。
列についてdfsして、Bの列の選び方を全て試す。
その際にok[i][j]により枝刈りする。
列を全て選び終わったら、そこから行をgreedyに選び、Aが作れるかを試す。
実は枝刈りなしでも通る。
ソースコード
int r,c,R,C; char A[20][20], B[20][20]; bool ok[20][20]; int anum[20],tmp[20]; bool dfs(int cur,int use){ if(use==c){ int i=0, j=0; for(;i<R&&j<r; i++){ while(i<R&&tmp[i]!=anum[j])i++; if(i<R)j++; } return j==r; } if(cur==C)return 0; if(ok[cur][use]){ rep(i,R)if(B[i][cur]=='1')tmp[i]|=1<<use; if(dfs(cur+1,use+1))return 1; rep(i,R)if(B[i][cur]=='1')tmp[i]^=1<<use; } return dfs(cur+1,use); } int main() { scanf("%d%d",&r,&c); rep(i,r){ scanf("%s",A[i]); rep(j,c)if(A[i][j]=='1')anum[i]|=1<<j; } scanf("%d%d",&R,&C); rep(i,R)scanf("%s",B[i]); rep(i,C)rep(j,c){ int k=0, l=0; for(;k<R&&l<r; k++){ while(k<R&&B[k][i]!=A[l][j])k++; if(k<R)l++; } if(l>=r)ok[i][j]=1; } puts(dfs(0,0)?"Yes":"No"); return 0; }