ABC051C Back and Forth
(niboshi time 30minutes)
int main() { cout <<setprecision(10); point S , G; cin >>S.x >> S.y >> G.x >> G.y; vector<string> road(4,""); int X , Y ; X = G.x - S.x; Y = G.y - S.y; //まず、ずっと→ の次に 上で行く経路J //G.x - S.x 個 、右に移動する rep(i,X){ road[0] += 'R'; } rep(i,Y){ road[0] += 'U'; } //一つ道順が求まった //二つ目は戻る道(遠回りで戻る) //まず右に一歩、下に Y+1 回 → 次に、左に X+1 回 最後に上に一回 //road[1] road[1] += 'R'; rep(i,Y+1){ road[1] +='D'; } rep(i,X+1){ road[1] += 'L'; } road[1] += 'U'; //次はずっと上からの右 rep(i,Y){ road[2] +='U'; } rep(i,X) road[2] +='R'; //最後は、戻る道順上1左X+1 下Y+1 右1 road[3] += 'U'; rep(i,X+1) road[3] += 'L'; rep(i,Y+1) road[3] += 'D'; road[3] +='R'; for(auto x : road){ cout << x ; } cout << endl; }
これなんですがついでにWAコードもはって置きます(一部抜粋)
//二つ目は戻る道(遠回りで戻る) //まず右に一歩、下に Y+1 回 → 次に、左に X+1 回 最後に上に一回 //road[1] road[1] += 'R'; rep(i,Y+1){ road[1] +='U'; } rep(i,X+1){ road[1] += 'L'; } road[1] += 'U'; //次はずっと上からの右 rep(i,Y){ road[2] +='U'; } rep(i,X) road[2] +='R'; //最後は、戻る道順上1左X+1 下Y+1 右1 road[3] += 'U'; rep(i,X+1) road[3] += 'L'; rep(i,Y+1) road[3] += 'U'; road[3] +='R';
これの何がいけないって、
上はUP の Uだな。
下はUNDER の U だなって思って U と R を追加してました…
これだと上も下もUであらわされてるから間違いってことです。
さて
解法
まず、4つの道順がどうなるかを考える。
① スタート地点をS(S.x,S.y),ゴール地点をG(T.x,T.y)とする
②通る道だけ考えるんだったら、SからGに行く4通りの道を求めればいい。
③このように考えて、同じ座標を踏んではいけないという制約から、一歩目は 右か左か上か、下に行く。の四通りしかないことが分かる。
- 一歩目が右の場合
- まずT.xまで右に進む
- その後、T.yまで上に進む
- 一歩目が上の場合
- まずT.yまで上に進む
- その後、T.xまで右に進む
この二つが、SからGに行く最短のルートである。
- 一歩目が左の場合
- まず一歩左に行く
- その後、T.y+1 まで上に行く
- その後 T.xまで右に行く
- 最後に一歩下に進む
- 一歩目が下の場合
- まず一歩下に行く
- その後T.x+1まで右に行く
- その後、T.yまで上に行く
- 最後に一歩左
(座標表記と、何歩という表記が混ざっていてわかりずらくなってます。すみません。
(一歩目が左の場合の,その後T.xまで右に行くとか、一歩目が下の場合のT.yまで上に行くっていうのは、
最初に左、もしくは下に動いてしまっているため,
T.xまたはT.yまで行くにはT.x-S.x +1歩 または T.y - S.y +1 歩、右、もしくは上に移動するということに注意してください)
このように4つの道について考えることが出来れば、あとはそのうちの二つをGからSに行くものとして上下左右を反転して文字列を作ればいい。
僕の場合は、road[4]で、4つの経路を求めることにして
road[0]がSからGに行く、この時Sからの一歩目が右
road[1]がGからSに行く、Gからの一歩目は右
road[2]がSからGに行く、Sからの一歩目は上
road[3]がGからSに行く、Gからの一歩目は上
というように、SからGへ行くときは距離最短、GからSへ戻るときは少し遠回りをしないといけない。という風にしました。
一応画像も貼っておくので良かったら見てね