Google Code Jam 2010 Round2 A.Elegant Diamond
本番で解けなかったやつorz
力もないのに見切り発車で実装するのがだめなのかもなあ。
問題概要
サイズkのダイアモンドが与えられる。これに数字をいくつか書き加えて「エレガントな」ダイアモンドにしたい。書き加える数の数の最小値を求めよ。
サイズkのダイアモンドとは、
1行目からk行目にそれぞれ1個、2個、...、k個の数字が並び、
k+1行目から2*k-1行目にそれぞれk-1個、k-2個、...、1個の数字が並んだものをいう。
ダイアモンドがエレガントであるとは、ダイアモンドが行に関して線対称であり、
列に関しても線対称であることをいう。
例)
1 2 2 3 4 3 2 2 1
k≦51である。
解法
すでにある対称軸を総当りで探す。
そのような対称軸のうち、元々の中心に最も近いところを大きなダイヤの中心とすればよい。
各数字は0-9であるので文字列のまま読み込む。
元々の中心と新たな中心のマンハッタン距離をdとすれば、
新たなダイヤのサイズはd+kである。(これらで大分実装が簡潔になるっぽい)
ソースコード
int k; vs dia; bool sayuu[200],jouge[200]; bool sayuuOK(int x) { rep(i,2*k-1)rep(j,2*k-1) if(0<=2*x-j&&2*x-j<2*k-1) if(dia[i][j]!=' '&&dia[i][2*x-j]!=' ') if(dia[i][j]!=dia[i][2*x-j])return 0; return 1; } bool jougeOK(int y) { rep(i,2*k-1)rep(j,2*k-1) if(0<=2*y-i&&2*y-i<2*k-1) if(dia[i][j]!=' '&&dia[2*y-i][j]!=' ') if(dia[i][j]!=dia[2*y-i][j])return 0; return 1; } int main() { int CS; cin>>CS; rep(cs,CS) { cin>>k; cin.ignore(); dia=vs(2*k-1); rep(i,2*k-1) { getline(cin,dia[i]); while(dia[i].size()<2*k-1)dia[i].pb(' '); } rep(i,2*k-1)sayuu[i]=sayuuOK(i); rep(i,2*k-1)jouge[i]=jougeOK(i); int ans=inf; rep(i,2*k-1)rep(j,2*k-1)if(sayuu[i]&&jouge[j]) ans=min(ans,abs(k-1-i)+abs(k-1-j)); ans=(ans+k)*(ans+k)-k*k; cout<<"Case #"<<cs+1<<": "<<ans<<endl; } return 0; }