{ }codelper
全探索二重ループbreak・continueP0345

腕の長さが違うてんびん

二本の腕の長さが違うこともあるてんびんがある。
左の腕の長さは a、右の腕の長さは b である。
左の皿にのせたおもりの重さに a を掛けた値と、右の皿にのせたおもりの重さに b を掛けた値が等しいとき、てんびんは水平になる。
おもりが n 個あり、1 番から n 番まで番号が付いている。
一行目に n、a、b が空白一つずつで区切って与えられる。
二行目におもりの重さ n 個が番号の順に空白一つずつで区切って与えられる。
異なるおもりを二つ選び、一つを左の皿に、一つを右の皿にのせて、てんびんを水平にしたい。
重さが同じでも番号が違えば異なるおもりである。
左にのせるおもりの番号と右にのせるおもりの番号を、この順に空白一つで区切って出力せよ。
方法がいくつもあるときは左のおもりの番号が最も小さいものを、それもいくつもあるときは右のおもりの番号が最も小さいものを出力する。
方法がなければ -1 を出力せよ。

入力
1 ≤ n ≤ 200、1 ≤ a ≤ 100、1 ≤ b ≤ 100、1 ≤ おもりの重さ ≤ 1,000(すべて整数、カンマなしの数字だけで与えられる)
出力
左のおもりの番号と右のおもりの番号を空白一つで区切った一行、方法がなければ -1
例 1 · stdin
5 2 3
4 6 9 2 3
stdout
2 1
例 2 · stdin
3 3 3
5 7 9
stdout
-1
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

左のおもりと右のおもりを二重のループですべて試し、最初に合った組で止めれば、それが答えです。
二重のループを一度に抜ける書き方は言語ごとに違います。
Java と JS・TS は外側のループに search: のようなラベルを付け、break search; で抜けます。
C は goto done; でループの外へ飛びます。
C++ の解答は i < n && !found のように、二つのループの条件に旗の変数を入れました。
Python・C#・Craykon の解答は探す部分を関数に分け、return(Craykon は 返す)で抜けました。
C# にはラベル付き break がありません。
落とし穴その一:ただの break は内側のループしか抜けません。
外側のループが回り続けて、あとから出てくる組が答えを上書きします。
例 1 で 2 1 ではなく 5 4 が出ます。
落とし穴その二:左と右は別の場所なので、(i, j) と (j, i) は別の方法です。
だから j も最初から最後まで回さなければなりません。
二つを選ぶ問題でよくやるように j を i + 1 から回すと、例 1 で右のおもりの番号のほうが小さい 2 1 を見られず、-1 が出ます。
落とし穴その三:同じおもりを両方の皿にのせることはできないので、i と j が違うかを確かめます。
忘れると、a と b が同じ例 2 で 1 1 が出ます。
落とし穴その四:左のおもりに a を、右のおもりに b を掛けます。
逆に掛けると例 1 で 1 2 が出ます。

Pythonmain.py · 11 行
def find(n, a, b, w):    for i in range(n):        for j in range(n):            if i != j and w[i] * a == w[j] * b:                return f"{i + 1} {j + 1}"   # return 하나로 두 겹의 반복을 모두 벗어난다    return "-1"  n, a, b = map(int, input().split())w = list(map(int, input().split()))print(find(n, a, b, w))
JavaScriptmain.js · 12 行
const [n, a, b, ...w] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let answer = "-1";// 바깥 반복에 이름표를 붙이면 break 이름표로 두 겹을 한 번에 벗어난다search: for (let i = 0; i < n; i++) {  for (let j = 0; j < n; j++) {    if (i !== j && w[i] * a === w[j] * b) {      answer = `${i + 1} ${j + 1}`;      break search;    }  }}console.log(answer);
TypeScriptmain.ts · 13 行
import { readFileSync } from "node:fs";const [n, a, b, ...w]: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let answer: string = "-1";// 바깥 반복에 이름표를 붙이면 break 이름표로 두 겹을 한 번에 벗어난다search: for (let i = 0; i < n; i++) {  for (let j = 0; j < n; j++) {    if (i !== j && w[i] * a === w[j] * b) {      answer = `${i + 1} ${j + 1}`;      break search;    }  }}console.log(answer);
JavaMain.java · 22 行
import java.util.Scanner; public class Main {    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int n = sc.nextInt(), a = sc.nextInt(), b = sc.nextInt();        int[] w = new int[n];        for (int i = 0; i < n; i++) w[i] = sc.nextInt();        String answer = "-1";        // 바깥 반복에 이름표를 붙이면 break 이름표로 두 겹을 한 번에 벗어난다        search:        for (int i = 0; i < n; i++) {            for (int j = 0; j < n; j++) {                if (i != j && w[i] * a == w[j] * b) {                    answer = (i + 1) + " " + (j + 1);                    break search;                }            }        }        System.out.println(answer);    }}
C#Main.cs · 24 行
using System; class Program{    // C#에는 이름표 break가 없어서 찾기를 함수로 빼고 return으로 벗어난다    static string Find(int n, int a, int b, int[] w)    {        for (int i = 0; i < n; i++)        {            for (int j = 0; j < n; j++)            {                if (i != j && w[i] * a == w[j] * b) return $"{i + 1} {j + 1}";            }        }        return "-1";    }     static void Main()    {        int[] first = Array.ConvertAll(Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries), int.Parse);        int[] w = Array.ConvertAll(Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries), int.Parse);        Console.WriteLine(Find(first[0], first[1], first[2], w));    }}
C++main.cpp · 23 行
#include <iostream>#include <vector> int main() {    int n, a, b;    std::cin >> n >> a >> b;    std::vector<int> w(n);    for (int& x : w) std::cin >> x;    int left = -1, right = -1;    bool found = false;    // 두 반복의 조건에 모두 !found를 넣어, 찾는 순간 두 겹이 다 멈추게 한다    for (int i = 0; i < n && !found; i++) {        for (int j = 0; j < n && !found; j++) {            if (i != j && w[i] * a == w[j] * b) {                left = i + 1;                right = j + 1;                found = true;            }        }    }    if (found) std::cout << left << " " << right << "\n";    else std::cout << -1 << "\n";}
Cmain.c · 18 行
#include <stdio.h> int main(void) {    int n, a, b, w[200];    scanf("%d %d %d", &n, &a, &b);    for (int i = 0; i < n; i++) scanf("%d", &w[i]);    for (int i = 0; i < n; i++) {        for (int j = 0; j < n; j++) {            if (i != j && w[i] * a == w[j] * b) {                printf("%d %d\n", i + 1, j + 1);                goto done;   /* break는 안쪽 반복만 벗어나므로 goto로 두 겹을 벗어난다 */            }        }    }    printf("-1\n");done:    return 0;}
Craykonmain.cray · 19 行
// 돌려주기 하나로 두 겹의 반복을 모두 벗어난다찾기(n, a, b, w){    繰り返す (i = 0; i < n; i++)    {        繰り返す (j = 0; j < n; j++)        {            もし (i != j && w[i] * a == w[j] * b)            {                返す i + 1 + " " + (j + 1);            }        }    }    返す "-1";} 첫줄 = コンソール.数読み();w = コンソール.数読み();コンソール.書く(찾기(첫줄[0], 첫줄[1], 첫줄[2], w));