{ }codelper
모두 해 보기함수를 값으로P0184

둥근 탁자 자리 규칙

손님 n명이 둥근 탁자에 앉는다. 자리는 0번부터 n − 1번까지 시계 방향으로 번호가 붙어 있고, n − 1번 자리와 0번 자리도 서로 이웃이다. 처음 적힌 손님은 늘 0번 자리에 앉고, 나머지 손님은 1번부터 n − 1번 자리에 한 명씩 앉는다. 두 자리 사이의 거리는 탁자를 따라 짧은 쪽으로 센 자리 차이다(자리 p, q라면 |p − q|와 n − |p − q| 가운데 작은 값). 규칙은 네 가지다. next A B: A와 B의 거리가 1이다. apart A B: A와 B의 거리가 1이 아니다. cw A B: B가 A의 바로 다음 자리(시계 방향)에 앉는다.
즉 B의 자리 = (A의 자리 + 1)을 n으로 나눈 나머지. far A B k: A와 B의 거리가 k 이상이다. 규칙 m개를 모두 지키는 앉는 방법의 수를 출력하라. 하나 이상이면, 그 가운데 0번 자리부터 차례로 이름을 적었을 때 사전 순으로 가장 앞서는 배치를 이름 사이에 빈칸 하나씩 띄워 한 줄 더 출력한다. 사전 순은 이름을 자리 순서대로 하나씩 비교하고, 이름끼리는 문자열 비교(알파벳 순, 앞부분이 같으면 짧은 쪽이 먼저)로 정한다.

입력
첫 줄에 n과 m, 둘째 줄에 서로 다른 이름 n개, 다음 m줄에 규칙 하나씩.
1 ≤ n ≤ 9, 0 ≤ m ≤ 20, 이름은 1~10글자 영어 소문자, 규칙의 A와 B는 서로 다른 손님, 1 ≤ k ≤ 9
출력
앉는 방법의 수.
1 이상이면 다음 줄에 사전 순으로 가장 앞선 배치
예시 1 · stdin
5 3
mina dan eve bo cal
next mina bo
cw dan eve
far mina cal 2
stdout
2
mina bo cal dan eve
예시 2 · stdin
2 1
bo al
apart al bo
stdout
0
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

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

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

손님이 9명이라도 나머지 8명을 앉히는 방법은 8!
= 40,320가지라 모두 해 볼 수 있어요.
자리를 1번부터 차례로 채우면서, 방금 앉힌 손님이 나오는 규칙 가운데 두 사람이 다 앉은 것만 바로 검사하고, 어긋나면 그 뒤는 보지 않아요(가지치기).
이름 순으로 앉혀 보면 처음 찾은 배치가 사전 순으로 가장 앞서요.
규칙은 읽을 때 검사 함수로 바꿔 목록에 담아 두면 앉힐 때는 종류를 다시 묻지 않고 부르기만 해요: Python lambda, JavaScript·TypeScript 화살표 함수 (sa, sb) => …(TypeScript는 type Check = (sa: number, sb: number) => boolean), Java BiPredicate<Integer, Integer>와 check.test(…), C# Func<int, int, bool>, C++ std::function<bool(int, int)>과 람다 [k](int sa, int sb) {…}, C는 함수 포인터 int (*check)(int, int, int)와 k를 함께 담은 구조체예요.
크레이콘은 람다가 없어서 모양 (sa, sb, k)를 맞춘 함수 네 개를 만들고, 사전 checks["far"] = 멀리;로 이름에서 함수를 찾아 [함수, a, b, k] 목록에 담은 뒤 r[0](sa, sb, r[3])로 불러요.
함정 ① 늦게 묶이는 k: Python에서 반복문 안의 lambda sa, sb: dist(sa, sb) >= k는 k의 값이 아니라 변수를 기억해서, 나중에 부를 때 마지막 규칙의 k를 봐요 — def at_least(k): return lambda …처럼 함수로 한 번 감싸요.
JavaScript의 var k도 반복마다 새로 생기지 않아 똑같이 깨지고, let/const는 반복마다 새로 생겨서 괜찮아요.
Java는 effectively final 변수만 람다가 가둘 수 있어 이 실수가 컴파일되지 않고, C#은 반복 몸통 안에서 만든 변수가 반복마다 따로예요.
C++는 [k]로 값을 복사해 가둬요.
② n − 1번과 0번이 이웃인 것을 잊고 거리를 |p − q|로만 재기.
③ cw의 방향을 거꾸로 하기.
④ 0번 자리를 고정하지 않아 돌려 앉힌 배치를 따로 세기.

Pythonmain.py · 63 줄
import sys  def main():    lines = sys.stdin.read().split("\n")    n, m = map(int, lines[0].split())    names = lines[1].split()    index = {name: i for i, name in enumerate(names)}     def dist(sa, sb):        """둥근 탁자에서 두 자리 사이의 짧은 쪽 거리"""        d = abs(sa - sb)        return min(d, n - d)     def at_least(k):        # k를 매개변수로 받아 가둔다. 반복문 안에서 lambda가 k를 바로 쓰면 마지막 k만 보게 된다        return lambda sa, sb: dist(sa, sb) >= k     makers = {        "next": lambda k: (lambda sa, sb: dist(sa, sb) == 1),        "apart": lambda k: (lambda sa, sb: dist(sa, sb) != 1),        "cw": lambda k: (lambda sa, sb: (sa + 1) % n == sb),        "far": at_least,    }    rules_of = [[] for _ in range(n)]  # 손님마다 그 손님이 나오는 규칙: (검사 함수, a, b)    for line in lines[2:2 + m]:        kind, x, y, *rest = line.split()        a, b = index[x], index[y]        check = makers[kind](int(rest[0]) if rest else 0)        rules_of[a].append((check, a, b))        rules_of[b].append((check, a, b))     order = sorted(range(1, n), key=lambda g: names[g])  # 이름 순으로 앉혀 보면 처음 찾은 배치가 사전 순으로 가장 앞선다    seat_of = [-1] * n    seat_of[0] = 0  # 처음 적힌 손님은 늘 0번 자리    at_seat = [0] * n    count = 0    first = None     def place(seat):        nonlocal count, first        if seat == n:            count += 1            if first is None:                first = " ".join(names[g] for g in at_seat)            return        for g in order:            if seat_of[g] != -1:                continue            seat_of[g] = seat            at_seat[seat] = g            # 둘 다 앉은 규칙만 바로 검사해서, 어긋나면 더 앉히지 않는다(가지치기)            if all(seat_of[a] < 0 or seat_of[b] < 0 or check(seat_of[a], seat_of[b]) for check, a, b in rules_of[g]):                place(seat + 1)            seat_of[g] = -1     place(1)    print(count)    if count > 0:        print(first)  main()
JavaScriptmain.js · 50 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [n, m] = lines[0].trim().split(/\s+/).map(Number);const names = lines[1].trim().split(/\s+/);const index = new Map(names.map((name, i) => [name, i])); // 둥근 탁자에서 두 자리 사이의 짧은 쪽 거리const dist = (sa, sb) => Math.min(Math.abs(sa - sb), n - Math.abs(sa - sb)); // 규칙 종류마다 "검사 함수를 만드는 함수". far는 k를 가둔 화살표 함수를 돌려준다const makers = {  next: () => (sa, sb) => dist(sa, sb) === 1,  apart: () => (sa, sb) => dist(sa, sb) !== 1,  cw: () => (sa, sb) => (sa + 1) % n === sb,  far: (k) => (sa, sb) => dist(sa, sb) >= k,};const rulesOf = Array.from({ length: n }, () => []); // 손님마다 그 손님이 나오는 규칙: { check, a, b }for (let i = 0; i < m; i++) {  const [kind, x, y, k] = lines[2 + i].trim().split(/\s+/);  const rule = { check: makers[kind](Number(k)), a: index.get(x), b: index.get(y) };  rulesOf[rule.a].push(rule);  rulesOf[rule.b].push(rule);} // 이름 순으로 앉혀 보면 처음 찾은 배치가 사전 순으로 가장 앞선다const order = [...Array(n).keys()].slice(1).sort((g, h) => (names[g] < names[h] ? -1 : 1));const seatOf = new Array(n).fill(-1);seatOf[0] = 0; // 처음 적힌 손님은 늘 0번 자리const atSeat = new Array(n).fill(0);let count = 0;let first = null; function place(seat) {  if (seat === n) {    count++;    if (first === null) first = atSeat.map((g) => names[g]).join(" ");    return;  }  for (const g of order) {    if (seatOf[g] !== -1) continue;    seatOf[g] = seat;    atSeat[seat] = g;    // 둘 다 앉은 규칙만 바로 검사해서, 어긋나면 더 앉히지 않는다(가지치기)    const ok = rulesOf[g].every(({ check, a, b }) => seatOf[a] < 0 || seatOf[b] < 0 || check(seatOf[a], seatOf[b]));    if (ok) place(seat + 1);    seatOf[g] = -1;  }} place(1);console.log(count > 0 ? `${count}\n${first}` : "0");
TypeScriptmain.ts · 58 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const [n, m] = lines[0].trim().split(/\s+/).map(Number);const names: string[] = lines[1].trim().split(/\s+/);const index = new Map<string, number>(names.map((name, i) => [name, i])); type Check = (sa: number, sb: number) => boolean;interface Rule {  check: Check;  a: number;  b: number;} // 둥근 탁자에서 두 자리 사이의 짧은 쪽 거리const dist = (sa: number, sb: number): number => Math.min(Math.abs(sa - sb), n - Math.abs(sa - sb)); // 규칙 종류마다 "검사 함수를 만드는 함수". far는 k를 가둔 화살표 함수를 돌려준다const makers: Record<string, (k: number) => Check> = {  next: () => (sa, sb) => dist(sa, sb) === 1,  apart: () => (sa, sb) => dist(sa, sb) !== 1,  cw: () => (sa, sb) => (sa + 1) % n === sb,  far: (k) => (sa, sb) => dist(sa, sb) >= k,};const rulesOf: Rule[][] = Array.from({ length: n }, () => []); // 손님마다 그 손님이 나오는 규칙for (let i = 0; i < m; i++) {  const [kind, x, y, k] = lines[2 + i].trim().split(/\s+/);  const rule: Rule = { check: makers[kind](Number(k)), a: index.get(x)!, b: index.get(y)! };  rulesOf[rule.a].push(rule);  rulesOf[rule.b].push(rule);} // 이름 순으로 앉혀 보면 처음 찾은 배치가 사전 순으로 가장 앞선다const order: number[] = [...Array(n).keys()].slice(1).sort((g, h) => (names[g] < names[h] ? -1 : 1));const seatOf: number[] = new Array<number>(n).fill(-1);seatOf[0] = 0; // 처음 적힌 손님은 늘 0번 자리const atSeat: number[] = new Array<number>(n).fill(0);let count = 0;let first: string | null = null; function place(seat: number): void {  if (seat === n) {    count++;    if (first === null) first = atSeat.map((g) => names[g]).join(" ");    return;  }  for (const g of order) {    if (seatOf[g] !== -1) continue;    seatOf[g] = seat;    atSeat[seat] = g;    // 둘 다 앉은 규칙만 바로 검사해서, 어긋나면 더 앉히지 않는다(가지치기)    const ok = rulesOf[g].every(({ check, a, b }) => seatOf[a] < 0 || seatOf[b] < 0 || check(seatOf[a], seatOf[b]));    if (ok) place(seat + 1);    seatOf[g] = -1;  }} place(1);console.log(count > 0 ? `${count}\n${first}` : "0");
JavaMain.java · 85 줄
import java.io.*;import java.util.*;import java.util.function.BiPredicate; public class Main {    record Rule(BiPredicate<Integer, Integer> check, int a, int b) {}     static int n;    static String[] names;    static List<List<Rule>> rulesOf = new ArrayList<>();    static Integer[] order;    static int[] seatOf, atSeat;    static long count = 0;    static String first = null;     // 둥근 탁자에서 두 자리 사이의 짧은 쪽 거리    static int dist(int sa, int sb) {        int d = Math.abs(sa - sb);        return Math.min(d, n - d);    }     static void place(int seat) {        if (seat == n) {            count++;            if (first == null) {                StringJoiner sj = new StringJoiner(" ");                for (int g : atSeat) sj.add(names[g]);                first = sj.toString();            }            return;        }        for (int g : order) {            if (seatOf[g] != -1) continue;            seatOf[g] = seat;            atSeat[seat] = g;            // 둘 다 앉은 규칙만 바로 검사해서, 어긋나면 더 앉히지 않는다(가지치기)            boolean ok = true;            for (Rule r : rulesOf.get(g)) {                if (seatOf[r.a()] >= 0 && seatOf[r.b()] >= 0 && !r.check().test(seatOf[r.a()], seatOf[r.b()])) {                    ok = false;                    break;                }            }            if (ok) place(seat + 1);            seatOf[g] = -1;        }    }     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        StringTokenizer st = new StringTokenizer(in.readLine());        n = Integer.parseInt(st.nextToken());        int m = Integer.parseInt(st.nextToken());        names = in.readLine().trim().split("\\s+");        Map<String, Integer> index = new HashMap<>();        for (int i = 0; i < n; i++) {            index.put(names[i], i);            rulesOf.add(new ArrayList<>());        }        for (int i = 0; i < m; i++) {            String[] p = in.readLine().trim().split("\\s+");            // 람다는 effectively final 변수만 가둘 수 있다: k는 반복마다 새로 만든다            final int k = p.length > 3 ? Integer.parseInt(p[3]) : 0;            BiPredicate<Integer, Integer> check = switch (p[0]) {                case "next" -> (sa, sb) -> dist(sa, sb) == 1;                case "apart" -> (sa, sb) -> dist(sa, sb) != 1;                case "cw" -> (sa, sb) -> (sa + 1) % n == sb;                default -> (sa, sb) -> dist(sa, sb) >= k;            };            Rule r = new Rule(check, index.get(p[1]), index.get(p[2]));            rulesOf.get(r.a()).add(r);            rulesOf.get(r.b()).add(r);        }        // 이름 순으로 앉혀 보면 처음 찾은 배치가 사전 순으로 가장 앞선다        order = new Integer[n - 1];        for (int i = 1; i < n; i++) order[i - 1] = i;        Arrays.sort(order, (g, h) -> names[g].compareTo(names[h]));        seatOf = new int[n];        Arrays.fill(seatOf, -1);        seatOf[0] = 0; // 처음 적힌 손님은 늘 0번 자리        atSeat = new int[n];        place(1);        System.out.println(count > 0 ? count + "\n" + first : "0");    }}
C#Main.cs · 79 줄
using System;using System.Collections.Generic;using System.Linq; class Program{    record Rule(Func<int, int, bool> Check, int A, int B);     static int n;    static string[] names;    static List<Rule>[] rulesOf;    static int[] order, seatOf, atSeat;    static long count = 0;    static string first = null;     // 둥근 탁자에서 두 자리 사이의 짧은 쪽 거리    static int Dist(int sa, int sb)    {        int d = Math.Abs(sa - sb);        return Math.Min(d, n - d);    }     static void Place(int seat)    {        if (seat == n)        {            count++;            if (first == null) first = string.Join(" ", atSeat.Select(g => names[g]));            return;        }        foreach (int g in order)        {            if (seatOf[g] != -1) continue;            seatOf[g] = seat;            atSeat[seat] = g;            // 둘 다 앉은 규칙만 바로 검사해서, 어긋나면 더 앉히지 않는다(가지치기)            bool ok = rulesOf[g].All(r => seatOf[r.A] < 0 || seatOf[r.B] < 0 || r.Check(seatOf[r.A], seatOf[r.B]));            if (ok) Place(seat + 1);            seatOf[g] = -1;        }    }     static void Main()    {        int[] nm = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();        n = nm[0];        int m = nm[1];        names = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        var index = new Dictionary<string, int>();        rulesOf = new List<Rule>[n];        for (int i = 0; i < n; i++)        {            index[names[i]] = i;            rulesOf[i] = new List<Rule>();        }        for (int i = 0; i < m; i++)        {            string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            int k = p.Length > 3 ? int.Parse(p[3]) : 0; // 반복 몸통 안에서 만든 변수라 람다마다 따로 갇힌다            Func<int, int, bool> check = p[0] switch            {                "next" => (sa, sb) => Dist(sa, sb) == 1,                "apart" => (sa, sb) => Dist(sa, sb) != 1,                "cw" => (sa, sb) => (sa + 1) % n == sb,                _ => (sa, sb) => Dist(sa, sb) >= k,            };            var r = new Rule(check, index[p[1]], index[p[2]]);            rulesOf[r.A].Add(r);            rulesOf[r.B].Add(r);        }        // 이름 순으로 앉혀 보면 처음 찾은 배치가 사전 순으로 가장 앞선다        order = Enumerable.Range(1, n - 1).OrderBy(g => names[g], StringComparer.Ordinal).ToArray();        seatOf = Enumerable.Repeat(-1, n).ToArray();        seatOf[0] = 0; // 처음 적힌 손님은 늘 0번 자리        atSeat = new int[n];        Place(1);        Console.WriteLine(count > 0 ? count + "\n" + first : "0");    }}
C++main.cpp · 82 줄
#include <algorithm>#include <cstdlib>#include <functional>#include <iostream>#include <map>#include <string>#include <vector> struct Rule {    std::function<bool(int, int)> check;    int a, b;}; int n;std::vector<std::string> names;std::vector<std::vector<Rule>> rulesOf;  // 손님마다 그 손님이 나오는 규칙std::vector<int> order, seatOf, atSeat;long long countAll = 0;std::string first; // 둥근 탁자에서 두 자리 사이의 짧은 쪽 거리int dist(int sa, int sb) {    int d = std::abs(sa - sb);    return std::min(d, n - d);} void place(int seat) {    if (seat == n) {        if (countAll++ == 0) {            for (int i = 0; i < n; i++) first += (i ? " " : "") + names[atSeat[i]];        }        return;    }    for (int g : order) {        if (seatOf[g] != -1) continue;        seatOf[g] = seat;        atSeat[seat] = g;        // 둘 다 앉은 규칙만 바로 검사해서, 어긋나면 더 앉히지 않는다(가지치기)        bool ok = std::all_of(rulesOf[g].begin(), rulesOf[g].end(), [](const Rule& r) {            return seatOf[r.a] < 0 || seatOf[r.b] < 0 || r.check(seatOf[r.a], seatOf[r.b]);        });        if (ok) place(seat + 1);        seatOf[g] = -1;    }} int main() {    int m;    std::cin >> n >> m;    names.resize(n);    std::map<std::string, int> index;    for (int i = 0; i < n; i++) {        std::cin >> names[i];        index[names[i]] = i;    }    rulesOf.assign(n, {});    for (int i = 0; i < m; i++) {        std::string kind, x, y;        std::cin >> kind >> x >> y;        std::function<bool(int, int)> check;        if (kind == "next") check = [](int sa, int sb) { return dist(sa, sb) == 1; };        else if (kind == "apart") check = [](int sa, int sb) { return dist(sa, sb) != 1; };        else if (kind == "cw") check = [](int sa, int sb) { return (sa + 1) % n == sb; };        else {            int k;            std::cin >> k;            check = [k](int sa, int sb) { return dist(sa, sb) >= k; };  // [k]: 지금 값을 복사해 가둔다        }        Rule r{check, index[x], index[y]};        rulesOf[r.a].push_back(r);        rulesOf[r.b].push_back(r);    }    // 이름 순으로 앉혀 보면 처음 찾은 배치가 사전 순으로 가장 앞선다    for (int i = 1; i < n; i++) order.push_back(i);    std::sort(order.begin(), order.end(), [](int g, int h) { return names[g] < names[h]; });    seatOf.assign(n, -1);    seatOf[0] = 0;  // 처음 적힌 손님은 늘 0번 자리    atSeat.assign(n, 0);    place(1);    std::cout << countAll << '\n';    if (countAll > 0) std::cout << first << '\n';}
Cmain.c · 99 줄
#include <stdio.h>#include <stdlib.h>#include <string.h> static int n; /* 둥근 탁자에서 두 자리 사이의 짧은 쪽 거리 */int dist(int sa, int sb) {    int d = abs(sa - sb);    return d < n - d ? d : n - d;} /* 규칙 검사 함수들: 모양(int, int, int)을 맞춰 두면 함수 포인터 하나로 부를 수 있다 */int rule_next(int sa, int sb, int k) { (void)k; return dist(sa, sb) == 1; }int rule_apart(int sa, int sb, int k) { (void)k; return dist(sa, sb) != 1; }int rule_cw(int sa, int sb, int k) { (void)k; return (sa + 1) % n == sb; }int rule_far(int sa, int sb, int k) { return dist(sa, sb) >= k; } typedef struct {    int (*check)(int, int, int); /* 함수 포인터 */    int a, b, k;} Rule; static char names[9][16];static Rule rules[20];static int rules_of[9][20], nrules_of[9]; /* 손님마다 그 손님이 나오는 규칙 번호 */static int order[9], seat_of[9], at_seat[9];static long count = 0;static char first[200]; int find(const char *s) {    for (int i = 0; i < n; i++)        if (strcmp(names[i], s) == 0) return i;    return -1;} void place(int seat) {    if (seat == n) {        if (count++ == 0) {            first[0] = '\0';            for (int i = 0; i < n; i++) {                if (i) strcat(first, " ");                strcat(first, names[at_seat[i]]);            }        }        return;    }    for (int oi = 0; oi < n - 1; oi++) {        int g = order[oi];        if (seat_of[g] != -1) continue;        seat_of[g] = seat;        at_seat[seat] = g;        /* 둘 다 앉은 규칙만 바로 검사해서, 어긋나면 더 앉히지 않는다(가지치기) */        int ok = 1;        for (int j = 0; j < nrules_of[g] && ok; j++) {            Rule *r = &rules[rules_of[g][j]];            if (seat_of[r->a] >= 0 && seat_of[r->b] >= 0 && !r->check(seat_of[r->a], seat_of[r->b], r->k)) ok = 0;        }        if (ok) place(seat + 1);        seat_of[g] = -1;    }} int by_name(const void *x, const void *y) {    return strcmp(names[*(const int *)x], names[*(const int *)y]);} int main(void) {    int m;    scanf("%d %d", &n, &m);    for (int i = 0; i < n; i++) scanf("%15s", names[i]);    for (int i = 0; i < m; i++) {        char kind[8], x[16], y[16];        scanf("%7s %15s %15s", kind, x, y);        Rule *r = &rules[i];        r->a = find(x);        r->b = find(y);        r->k = 0;        if (strcmp(kind, "next") == 0) r->check = rule_next;        else if (strcmp(kind, "apart") == 0) r->check = rule_apart;        else if (strcmp(kind, "cw") == 0) r->check = rule_cw;        else {            r->check = rule_far;            scanf("%d", &r->k);        }        rules_of[r->a][nrules_of[r->a]++] = i;        rules_of[r->b][nrules_of[r->b]++] = i;    }    /* 이름 순으로 앉혀 보면 처음 찾은 배치가 사전 순으로 가장 앞선다 */    for (int i = 1; i < n; i++) order[i - 1] = i;    qsort(order, n - 1, sizeof(int), by_name);    for (int i = 0; i < n; i++) seat_of[i] = -1;    seat_of[0] = 0; /* 처음 적힌 손님은 늘 0번 자리 */    at_seat[0] = 0;    place(1);    printf("%ld\n", count);    if (count > 0) printf("%s\n", first);    return 0;}
Craykonmain.cray · 127 줄
// 둥근 탁자에서 두 자리 사이의 짧은 쪽 거리거리(sa, sb){    d = 수학.절댓값(sa - sb);    돌려주기 수학.작은수(d, n - d);} // 규칙 검사 함수들. 크레이콘에는 람다가 없으니 모양(sa, sb, k)을 맞춘 함수를 이름으로 넘긴다이웃(sa, sb, k){    돌려주기 거리(sa, sb) == 1;} 떨어짐(sa, sb, k){    돌려주기 거리(sa, sb) != 1;} 시계방향(sa, sb, k){    돌려주기 (sa + 1) % n == sb;} 멀리(sa, sb, k){    돌려주기 거리(sa, sb) >= k;} // 이름 순 비교(정렬 기준 함수)이름순(g, h){    만약 (names[g] < names[h])    {        돌려주기 -1;    }    돌려주기 1;} 앉히기(seat){    만약 (seat == n)    {        count += 1;        만약 (count == 1)        {            first = names[atSeat[0]];            반복 (s = 1; s < n; s++)            {                first += " " + names[atSeat[s]];            }        }        돌려주기;    }    각각 (g 에서 order)    {        만약 (seatOf[g] == -1)        {            seatOf[g] = seat;            atSeat[seat] = g;            // 둘 다 앉은 규칙만 바로 검사해서, 어긋나면 더 앉히지 않는다(가지치기)            ok = 참;            각각 (r 에서 rulesOf[g])            {                sa = seatOf[r[1]];                sb = seatOf[r[2]];                만약 (sa >= 0 && sb >= 0 && !r[0](sa, sb, r[3]))                {                    ok = 거짓;                    그만;                }            }            만약 (ok)            {                앉히기(seat + 1);            }            seatOf[g] = -1;        }    }} nm = 콘솔.수들읽기();n = nm[0];m = nm[1];names = 콘솔.줄읽기().공백제거().나누기(" ");index = 사전();rulesOf = [];반복 (i = 0; i < n; i++){    index[names[i]] = i;    rulesOf.넣기([]);}checks = 사전(); // 규칙 이름 → 검사 함수checks["next"] = 이웃;checks["apart"] = 떨어짐;checks["cw"] = 시계방향;checks["far"] = 멀리;반복 (i = 0; i < m; i++){    p = 콘솔.줄읽기().공백제거().나누기(" ");    kval = 0;    만약 (p.개수 > 3)    {        kval = p[3].수로변환();    }    rule = [checks[p[0]], index[p[1]], index[p[2]], kval]; // [검사 함수, a, b, k]    rulesOf[rule[1]].넣기(rule);    rulesOf[rule[2]].넣기(rule);} // 이름 순으로 앉혀 보면 처음 찾은 배치가 사전 순으로 가장 앞선다order = [];반복 (i = 1; i < n; i++){    order.넣기(i);}order.정렬(이름순);seatOf = 새목록(n, -1);seatOf[0] = 0; // 처음 적힌 손님은 늘 0번 자리atSeat = 새목록(n, 0);count = 0;first = "";앉히기(1);콘솔.쓰기(count);만약 (count > 0){    콘솔.쓰기(first);}