問題
A,B,C,Dがトライアスロン(※)をしました。
それぞれの証言から順位を推理し、1位から順にA,B,C,Dを並べ替えてください。
※:水泳→自転車→マラソンの順で争う競技。マラソンの順位が最終的な順位
【証言】
A「水泳も自転車も順位は同じだったけど、マラソンで二人に抜かれちゃった。」
B「自転車でDを抜いて、そのあとはゴールまで Dには抜かれてないよ。」
C「水泳で3位だったけど、ゴールするまで3位より上になったことはなかったよ。ちぇ。」
D「自転車で調子が悪くて 4位に落ちちゃったけど、結局水泳と同じ順位でゴールできた。」
プログラム
const 順位 = {
A: { 水泳: 0, 自転車: 0, マラソン: 0 },
B: { 水泳: 0, 自転車: 0, マラソン: 0 },
C: { 水泳: 0, 自転車: 0, マラソン: 0 },
D: { 水泳: 0, 自転車: 0, マラソン: 0 },
};
const 満たすべき条件たち = [
// A「水泳も自転車も順位は同じだったけど、マラソンで二人に抜かれちゃった。」
() => 順位.A.水泳 === 順位.A.自転車,
() => 順位.A.マラソン === 順位.A.自転車 + 2,
// B「自転車でDを抜いて、そのあとはゴールまで Dには抜かれてないよ。」
() => 順位.B.自転車 < 順位.D.自転車,
() => 順位.B.マラソン < 順位.D.マラソン,
// C「水泳で3位だったけど、ゴールするまで3位より上になったことはなかったよ。ちぇ。」
() => 順位.C.水泳 === 3,
() => 順位.C.自転車 >= 3 && 順位.C.マラソン >= 3,
// D「自転車で調子が悪くて 4位に落ちちゃったけど、結局水泳と同じ順位でゴールできた。」
() => 順位.D.自転車 === 4,
() => 順位.D.水泳 === 順位.D.マラソン,
];
function permute(nums) {
const result = [];
function backtrack(current, remaining) {
if (remaining.length === 0) {
result.push(current);
return;
}
for (let i = 0; i < remaining.length; i++) {
const newCurrent = current.concat([remaining[i]]);
const newRemaining = remaining.slice(0, i).concat(remaining.slice(i + 1));
backtrack(newCurrent, newRemaining);
}
}
backtrack([], nums);
return result;
}
const 順位組み合わせ一覧 = permute([1, 2, 3, 4]);
loop:
for (const 水泳順位 of 順位組み合わせ一覧) {
順位.A.水泳 = 水泳順位[0];
順位.B.水泳 = 水泳順位[1];
順位.C.水泳 = 水泳順位[2];
順位.D.水泳 = 水泳順位[3];
for (const 自転車順位 of 順位組み合わせ一覧) {
順位.A.自転車 = 自転車順位[0];
順位.B.自転車 = 自転車順位[1];
順位.C.自転車 = 自転車順位[2];
順位.D.自転車 = 自転車順位[3];
for (const マラソン順位 of 順位組み合わせ一覧) {
順位.A.マラソン = マラソン順位[0];
順位.B.マラソン = マラソン順位[1];
順位.C.マラソン = マラソン順位[2];
順位.D.マラソン = マラソン順位[3];
let 条件が満たされているか = true;
for (const 満たすべき条件 of 満たすべき条件たち) {
if (!満たすべき条件()) {
条件が満たされているか = false;
break;
}
}
if (条件が満たされているか) {
break loop;
}
}
}
}
console.log(
[
{ 名前: "A", 順位: 順位.A.マラソン },
{ 名前: "B", 順位: 順位.B.マラソン },
{ 名前: "C", 順位: 順位.C.マラソン },
{ 名前: "D", 順位: 順位.D.マラソン },
]
.sort((a, b) => a.順位 - b.順位)
.map(e => e.名前)
.join("")
);
結果
BDAC
その他
論理的な解き方が知りたい方は以下のサイトを見てください。
Prolog版