AOJ_0209 写真に写っている景色は?
問題
略
解法
計算量はどんなに悪くても n^2 * m^2 * 4 = 10000 * 250 * 4 = 10000000 より少ないので、
全探索すれば大丈夫。正確な計算をすると、もっと小さくなる。
回転させた図形の作り方
1、回転させる二次元配列(p[x][y])に、
(下から上に一列とりpn[x][y]の空いている一番上の行に入れる)を左から右へ繰り返し、
新しい二次元配列 pn[x][y] を作る。
2、pn[x][y]に1を適用しさらに回転させた図形を作っていく。
これを繰り返せば、右に90度ずつ回転させた配列が得られる
コードのネストがなんかすごいことになってしまった。
実装
#include <cstdio> #include <algorithm> const int MAX_N = 100; const int MAX_M = 50; int N, M; int pic[MAX_N][MAX_N]; int p[4][MAX_M][MAX_M]; int ansx, ansy; //写真の切れ端をくるくる回す関数 void kurukuru(){ for(int k = 1; k < 4; k++){ int x = 0; for(int i = M - 1; i >= 0; i--){ for(int j = 0; j < M; j++) p[k][x][j] = p[k - 1][j][i]; x++; } } } bool c(int x, int y, int k){ for(int j = 0; j < M; j++){ for(int i = 0; i < M; i++){ if(p[k][i][j] == -1) continue; if(p[k][i][j] != pic[x + i][y + j]){ return false; } } } return true; } void solve(){ for(int y = 0; y <= N - M; y++){ for(int x = 0; x <= N - M; x++){ //回転させた4種類の切れ端を順に試す for(int k = 0; k < 4; k++){ if(c(x, y, k)){ //ぴったり! for(int j = 0; j < M; j++){ for(int i = 0; i < M; i++){ if(p[k][i][j] != -1){ ansx = i + x + 1; ansy = j + y + 1; return; } } } } } } } ansx = -1; ansy = -1; } int main(){ while(scanf("%d %d", &N, &M) && N){ for(int i = 0; i < N; i++) for(int j = 0; j < N; j++) scanf("%d", &pic[j][i]); for(int i = 0; i < M; i++) for(int j = 0; j < M; j++) scanf("%d", &p[0][j][i]); kurukuru(); solve(); if(ansx != -1) printf("%d %d\n", ansx, ansy); else printf("NA\n"); } return 0; }