AtCoder ABC 054 A&B&C
A問題
- AとBの数を比べる
- 2<3<4<5<6<7<8<9<10<11<12<13<1 の順
- 同じ数ならDraw
- 1が最強なのでどちらかが1だったら其方の勝ち
- 同じ数でもなく、1でもないなら数が大きいほうが勝ち
int alice = nextInt();
int bob = nextInt();
if (alice == bob) {
out.println("Draw");
} else if (alice == 1) {
out.println("Alice");
} else if (bob == 1) {
out.println("Bob");
} else if (alice != bob) {
out.println(alice > bob ? "Alice" : "Bob");
}
out.println("");
B問題
説明はソースにインラインで記載
private void solveB() {
int numN = nextInt();
int numM = nextInt();
String[] wkA = new String[numN];
String[] wkB = new String[numM];
for (int i = 0; i < wkA.length; i++) {
wkA[i] = next();
}
for (int i = 0; i < wkB.length; i++) {
wkB[i] = next();
}
boolean res = chkB(wkA, 0, wkB, 0);
out.println(res ? "Yes" : "No");
}
private boolean chkB(String[] wkA, int currentA, String[] wkB, int aPos) {
boolean res = false;
//wkAの残りがwkBより少ない場合は探索できない
if (wkA.length - currentA < wkB.length) {
return false;
}
//wkA[]の残り長がwkB[]より少ない場合は探索できない
if (wkA[currentA].length() - aPos < wkB[0].length()) {
return false;
}
//まず、Aの位置を決める
//そのために、BのcurrentB列目がAのcurrentA列目どこに出現するのか確認
//Aの横軸の値を取得
//※Aの横軸は複数取得できる可能性がある。
//BのcurrentB列目がAのcurrentA列目どこに出現するのか確認
boolean aPosWk = wkA[currentA].startsWith(wkB[0], aPos);
if (aPosWk) {
//Aの横軸出現したらcurrentA+1の列の横軸から、B列のcurrentB+1が出現するのか確認
for (int i = 0; i < wkB.length; i++) {
res = wkA[currentA + i].startsWith(wkB[0 + i], aPos);
if (!res) {
break;
}
}
}
//Aの横軸が出現しなかったら、aPos+1列目を検索
//このaPosでは一致しない場合、aPosを+1して再探索
if (!res) {
//B列のcurrentB+1が出現しなかったら、もう一度、Aの横軸を検索
int len = wkA[currentA].indexOf(wkB[0], aPos + 1);
//横列にまだ候補があるので再検索
if (len >= 0) {
res = chkB(wkA, currentA, wkB, len);
}
}
//aPosが0でない場合は次のcurrentIdを
if (!res && aPos == 0) {
//Aの横軸が出現しなかったら、currentA+1行目を検索
res = chkB(wkA, currentA + 1, wkB, 0);
}
return res;
}
C問題
とりあえず、入力例1を隣接行列として表現する。
入力1
1 2
1 3
2 3
変換(行ける所にTrueをはめる)
1 | 2 | 3 | |
---|---|---|---|
1 | T | T | |
2 | T | T | |
3 | T | T |
無向グラフなので対象行列となる。
- まずは、入力を対象行列に変換
- 行ける位置にtrueを代入
- 行った先をmemoするために、numNと同じ長さのboolean[]を生成
- 検索自体は再帰で行う
- 最初の1か所目は訪れ済み
private void solveC() {
int numN = nextInt();
int numM = nextInt();
boolean[][] wk = new boolean[numN][numN];
for (int i = 0; i < numM; i++) {
int iA = nextInt();
int iB = nextInt();
wk[iA - 1][iB - 1] = true;
wk[iB - 1][iA - 1] = true;
}
boolean[] visited = new boolean[numN];
visited[0] = true;
int res = chkSolveC(wk, 0, visited);
out.println(res);
}
- 再帰の終了条件
- すでに訪れたところがあるなら+1して終了
- 次に進む条件
- 隣接行列上行ける(wk[][]でtrue) & まだ訪れたことが無い(visited[]でfalse)
再帰だとchkSolveCを呼び出す際にcurrentIを+1したくなったけど、よく考えたら隣接行列で行ける所のiを取り出して引数のcurrentIとして渡しているので+1なんて不要。
private int chkSolveC(boolean[][] wk, int currentI, boolean[] visited) {
boolean res = true;
for (int i = 0; i < visited.length; i++) {
if (!visited[i]) {
res = false;
}
}
if (res) {
return 1;
}
int resCnt = 0;
boolean[] wkG = wk[currentI];
for (int i = 0; i < wkG.length; i++) {
if (wkG[i] && !visited[i]) {
visited[i] = true;
resCnt += chkSolveC(wk, i, visited);
visited[i] = false;
}
}
return resCnt;
}