2010-06-07
GCJ 2010 Round 2 : A. Elegant Diamond
教訓
・問題はよく嫁
・処理しやすい座標系を考える
・斜め移動は(自分の場合)バグりやすいのでご用心
サンプルは通るけどA-smallでIncorrect、なコード
- enhanced diamondの中心になりうるすべての点について、symmetricなdiamondが作れるか調べてるだけ。O(k^4)。
- アイデアはコンテスト中に思いついたままだけど、実装するのに時間かかってるしA-small通らないしAからやってても駄目だったなと…泣
#include <iostream>
#include <sstream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <stack>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <cstdio>
#include <cmath>
#include <cctype>
using namespace std;
#define sz(a) int((a).size())
#define pb push_back
#define rep(var,n) for(int var=0,lim=(n);var<lim;var++)
#define REP(var,ar) for(int var=0,lim=(ar).size();var<lim;var++)
#define FOR(var,from,to) for(int var=(from);var<=(to);var++)
#define all(c) (c).begin(),(c).end()
#define found(s,e) ((s).find(e)!=(s).end())
#define skiplf() do{char buf[256];cin.getline(buf,256);}while(0)
#define X 52
#define W (X*2+1)
char raw[W][W];
bool centerable[W][W];
int k,l,w;
#define VISUALIZE 1
bool test(int cy,int cx){
rep(i,l){
int dy=i-w, ay=cy*2-dy; /// (ax+dx)/2=cx, ax=2cx-dx
if(ay<-X || X<ay) continue;
rep(j,l){
int dx=j-w, ax=cx*2-dx;
if(ax<-X || X<ax) continue;
if (abs(dx)+abs(dy)>w) continue;
int d=raw[X+dy][X+dx], a=raw[X+ay][X+ax];
if(d<0 || a<0) continue;
if(d!=a) return false;
}
}
return true;
}
int main(){
int T;cin>>T;
rep(t,T){
rep(i,W) rep(j,W) { raw[i][j]=-1; centerable[i][j]=false; }
cin>>k; l=k*2-1; w=k-1;
skiplf();
rep(i,l){
char buf[256]; cin.getline(buf,256);
int dy=i-w;
rep(j,l){
if(!buf[j]) break;
if(buf[j]<'0' || '9'<buf[j]) continue;
int dx=j-w;
raw[X+dy][X+dx] = buf[j]-'0';
}
}
#ifdef VISUALIZE
rep(i,l){
int dy=i-w;
rep(j,l){
int dx=j-w;
int n=raw[X+dy][X+dx];
if(n>=0)
printf(" %d", n);
else
printf(" ");
}
cout<<endl;
}
#endif
// x:[-w,+w], y:[-w,+w]; abs(x)+abs(y)<=w
int minarea = 99999999;
rep(i,l){
int dy=i-w;
rep(j,l){
int dx=j-w;
if (abs(dx)+abs(dy)>w) continue; // |dx|+|dy|<=w
if (centerable[X+dy][X+dx] = test(dy,dx)) {
int abx=abs(dx), aby=abs(dy);
int k_ = k + abx+aby;
minarea=min(minarea,k_*k_);
}
}
}
#ifdef VISUALIZE
rep(i,l){
int dy=i-w;
rep(j,l){
int dx=j-w;
if (abs(dx)+abs(dy)>w) printf(" ");
else printf(" %c", centerable[X+dy][X+dx] ? 'o' : 'x');
}
cout<<endl;
}
#endif
printf("Case #%d: %d\n", 1+t, minarea-k*k);
}
return 0;
}
間違い発見
- あ、これでは(上下左右対称ではなく)点対称か…orz (nodchipさんのエントリを見て気がつきました)
- というわけで上下左右対称に書き直したらsmall/largeともに通った。
- 主な書き換えポイントはtest()、あと探索範囲をダイヤモンド内だけでなくダイヤモンドを含む(45度ずれた)正方形に広げた
bool test(int cy,int cx){ /// ★MODIFIED
rep(i,l){
int dy=i-w, ay=dy, by=cy*2-dy;
rep(j,l){
int dx=j-w, ax=cx*2-dx, bx=dx;
int d=raw[X+dy][X+dx]; if (d<0) continue;
int a=(-w<=ax && ax<=w && -w<=ay && ay<=w)? raw[X+ay][X+ax] : -1;
if (a>=0 && d!=a) return false;
int b=(-w<=bx && bx<=w && -w<=by && by<=w)? raw[X+by][X+bx] : -1;
if (b>=0 && d!=b) return false;
}
}
return true;
}
int main(){
int T;cin>>T;
rep(t,T){
rep(i,W) rep(j,W) { raw[i][j]=-1; centerable[i][j]=false; }
cin>>k; l=k*2-1; w=k-1;
skiplf();
rep(i,l){
char buf[256]; cin.getline(buf,256);
int dy=i-w;
rep(j,l){
if(!buf[j]) break;
if(buf[j]<'0' || '9'<buf[j]) continue;
int dx=j-w;
raw[X+dy][X+dx] = buf[j]-'0';
}
}
#ifdef VISUALIZE
rep(i,l){
int dy=i-w;
rep(j,l){
int dx=j-w;
int n=raw[X+dy][X+dx];
if(n>=0)
printf(" %d", n);
else
printf(" ");
}
cout<<endl;
}
#endif
// x:[-w,+w], y:[-w,+w]; abs(x)+abs(y)<=w
int minarea = 99999999;
rep(i,l){
int dy=i-w;
rep(j,l){
int dx=j-w;
// if (abs(dx)+abs(dy)>w) continue; /// ★REMOVED
if (centerable[X+dy][X+dx] = test(dy,dx)) {
int abx=abs(dx), aby=abs(dy);
int k_ = k + abx+aby;
minarea=min(minarea,k_*k_);
}
}
}
#ifdef VISUALIZE
rep(i,l){
int dy=i-w;
rep(j,l){
int dx=j-w;
printf(" %c", centerable[X+dy][X+dx] ? 'o' : '.'); /// ★CHANGED
}
cout<<endl;
}
#endif
printf("Case #%d: %d\n", 1+t, minarea-k*k);
}
return 0;
}
補足
if (centerable[X+dy][X+dx] = test(dy,dx)) {
とか書いてるけど if ( (c.. = t..) == true ) の意味ですからね。仕事コードではこういう書き方は厳禁ですよ!
コメント
トラックバック - https://topcoder-g-hatena-ne-jp.jag-icpc.org/n4_t/20100607