{ }codelper
모두 해 보기겹친 반복멈추기·건너뛰기P0345

팔 길이가 다른 저울

두 팔의 길이가 서로 다를 수 있는 저울이 있다. 왼쪽 팔의 길이는 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()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

왼쪽 추와 오른쪽 추를 두 겹의 반복으로 모두 대어 보고, 처음 맞는 짝에서 멈추면 그것이 답이에요.
두 겹의 반복을 한 번에 벗어나는 방법이 언어마다 달라요.
Java와 JS·TS는 바깥 반복에 search: 같은 이름표를 붙이고 break search;로 벗어나요.
C는 goto done;으로 반복 밖으로 건너뛰어요.
C++은 i < n && !found처럼 두 반복의 조건에 깃발 변수를 넣었어요.
Python·C#·크레이콘은 찾는 부분을 함수로 빼고 return(크레이콘은 돌려주기)으로 벗어났어요.
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));