AtCoder振り返りその1(京セラプログラミングコンテスト2023)
初めに
以前から競技プログラミングのAtCoderには参加しておりました、ブログを書き始めたため今回から振り返りを書いていこうと思います。
今後も可能な限り競技プログラミング参加後、記事を書き、振り返りを行い、提出したコードに満足行っていなかったら都度書き直したいと思います。
A問(A - Water Station)
問題はこちら→A - Water Station
問題内容を読んでみると要は0~100の数字が入力されるのでその数字を5倍数になるよう四捨五入した数字を出力すると書いてあります。
A問提出コード
#include<stdio.h> int main(void) { int n; scanf("%d", &n); printf("%d", n / 5 * 5 + ((n % 5 >= 3) ? 5 : 0)); }
出力する際に計算を行っています。
計算内容はn / 5 * 5部分で5の倍数に切り捨てを行い+((n % 5 >= 3) ? 5 : 0)の部分で5で割ったあまりが3以上であれば5を足し、そうでなければ0を足しています。
B問(B - ABCDEFG)
問題はこちら→B - ABCDEFG
直線状にA~Fまでそれぞれの点があり、隣あっているアルファベットの距離のみ説明にあります。
A~F中で2つの異なる点q、点pを入力し点qと点pの距離を出力するものです。
B問提出コード
#include<stdio.h> #include <stdlib.h> int main(void) { char p,q; int a[7] = {0,3,4,8,9,14,23}; scanf(" %c %c", &p, &q); printf("%d", abs(a[p - 'A'] - a[q - 'A'])); return 0; }
始めにint aにA点を0とした際の各点のAとの距離を配列に入れます。
点q、点pの入力後に、点qのAとの距離-点pのAとの距離をおこないabs関数で絶対値を出しマイナスが出ないよう出力を行います。
かなり簡潔なコードが書けました。直すとしたらaという変数名を使用したとこのみです。
C問(C - Snuke the Cookie Picker)
問題はこちら→C - Snuke the Cookie Picker
長方形で一辺が2~500マスのグリットがありその中に2~500マスの長方形が入っておりその長方形が1マスだけかけているのでそのマスの座標を出力するものです。
グリッドは'.'であらわし中の長方形は'#'です、かけたマスはグリッドと同じ'.'で表します。
C問提出コード
#include<stdio.h> int main(void) { int h, w; char s[501][501] = { 0 }; scanf("%d %d", &h, &w); for (int i = 0; i < h; i++) { scanf("%s", &s[i]); } for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if (s[i][j] == '.') { if ((s[((0 <= i || i <= h) ? i: 0) + 1][((0 <= j || j <= h) ? j: 0)] == '#' && s[((0 <= i || i <= h) ? i: 0) - 1] == '#') || (s[((0 <= i || i <= h) ? i: 0) + 1][((0 <= j || j <= h) ? j: 0)] == '#' && s[((0 <= i || i <= h) ? i: 0)][((0 <= j || j <= h) ? j: 0)+1] == '#') || (s[((0 <= i || i <= h) ? i: 0) + 1][((0 <= j || j <= h) ? j: 0)] == '#' && s[((0 <= i || i <= h) ? i: 0)][((0 <= j || j <= h) ? j: 0) - 1] == '#') || (s[((0 <= i || i <= h) ? i: 0)-1][((0 <= j || j <= h) ? j: 0)] == '#' && s[((0 <= i || i <= h) ? i: 0)][((0 <= j || j <= h) ? j: 0) + 1] == '#') || (s[((0 <= i || i <= h) ? i: 0) - 1][((0 <= j || j <= h) ? j: 0)] == '#' && s[((0 <= i || i <= h) ? i: 0)][((0 <= j || j <= h) ? j: 0) - 1] == '#') || (s[((0 <= i || i <= h) ? i: 0)][((0 <= j || j <= h) ? j: 0)+1] == '#' && s[((0 <= i || i <= h) ? i: 0)][((0 <= j || j <= h) ? j: 0) - 1] == '#')) { printf("%d %d\n", i+1, j+1); return 0; } } } } return 0; }
一目でわかる見ずらいコードですね。
入力後に二重forループで1マスずつ条件が一致しているか見いき、条件式で見るマスの上下左右のマスに2箇所以上'#'があった場合との座標を返すものとなっております。
ACと出たのですが見返してみると条件式の中身は左右で1マス以上と上下で1マス以上'#'があればよくてさらにコードが誤っておりこのままでは範囲外アクセスしてしまいます。
修正したコードがこちらになります。
#include<stdio.h> int main(void) { int h, w; char s[501][501] = { 0 }; scanf("%d %d", &h, &w); for (int i = 0; i < h; i++) { scanf("%s", &s[i]); } for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if (s[i][j] == '.') { if ((i + 1 > h ? s[i][j] : s[i + 1][j]) == '#' || (i - 1 < 0 ? s[i][j] : s[i - 1][j]) == '#') { if ((j + 1 > w ? s[i][j] : s[i][j + 1]) == '#' || (j - 1 < 0 ? s[i][j] : s[i][j - 1]) == '#') { printf("%d %d\n", i + 1, j + 1); return 0; } } } } } return 0; }
範囲外アクセスと条件式を書き直し、複数のif分に分けたため見やすくなりました。
感想
今回はA問B問が比較的簡単ですぐに早々に解けて、なおかつ簡潔なコードを書くことができました。
これまで何度かAtCoderに参加しておりましたが、初めてC問を解くことができたので、成長を感じました。