{ }codelper
交换元素复制列表遍历列表P0176

换座位之后挪动的学生

教室里有一排 n 个座位,座位号从左到右为 1, 2, …, n。
第一行给出 n,第二行按座位顺序给出最初坐在各座位上的 n 个学生的名字,用一个空格隔开。
第三行给出交换次数 m,接下来 m 行每行给出一次交换 "i j"。
班主任按给出的顺序进行这些交换。
交换 "i j" 表示 i 号座位的学生和 j 号座位的学生互换座位。
如果 i 和 j 相同,什么也不发生。
所有交换结束后,在第一行按座位顺序输出学生名字,用一个空格隔开。
第二行输出最初座位和最后座位不同的学生人数 k。
接下来 k 行,对每个这样的学生输出 "名字 最初座位 最后座位",用一个空格隔开。
这 k 行按最初座位号从小到大输出。
挪动过几次但最后回到最初座位的学生不计入。
如果 k 为 0,只输出到第二行的 0 为止。

输入
1 ≤ n ≤ 1000,0 ≤ m ≤ 2000,1 ≤ i, j ≤ n。
名字由 1 ~ 10 个英文小写字母组成,互不相同
输出
第一行为最后座位顺序的名字,第二行为 k,接下来 k 行为 "名字 最初座位 最后座位"
样例 1 · stdin
5
mina joon sora dan kai
3
1 3
2 5
3 1
stdout
mina kai sora dan joon
2
joon 2 5
kai 5 2
样例 2 · stdin
3
ari bo cy
3
1 2
2 3
3 1
stdout
ari cy bo
2
bo 2 3
cy 3 2
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

要保留最初的座位,必须在交换前复制列表。
陷阱一:start = seats 不是复制,只是给同一个列表再起一个名字,所以每次交换在两个名字上都看得见,挪动的学生总是 0 人。
Python、JS、TS、Java、C# 的列表和数组以及 Craykon 的列表都是这样指向同一个对象。
复制的方法:Python seats[:]、list(seats),JS/TS [...seats]、slice(),Java seats.clone(),C# (string[])seats.Clone(),Craykon seats.子列表(0, seats.数量)(韩文 부분목록、개수)。
只有 C++ 的 std::vector 用 = 会逐个复制元素;C 的数组根本不能用 = 赋值,要用 memcpy 或 strcpy 复制。
交换两个元素:Python a[i], a[j] = a[j], a[i],JS/TS [a[i], a[j]] = [a[j], a[i]],C# 元组 (a[i], a[j]) = (a[j], a[i]),C++ std::swap(a[i], a[j]);Java、C、Craykon 用临时变量 tmp(C 字符串用三次 strcpy)。
陷阱二:不用临时变量写成 a[i] = a[j]; a[j] = a[i];,第一行已经覆盖了 a[i],两个座位就变成同一个名字。
最后查找每个学生现在的座位时,先建一次 名字 → 座位 的字典,就不必为每个学生重新查找。

Pythonmain.py · 19 行
import sys data = sys.stdin.read().split()n = int(data[0])seats = data[1:1 + n]start = seats[:]            # 처음 자리를 따로 복사해 둔다(start = seats 는 같은 목록에 이름만 둘)m = int(data[1 + n])pos = 2 + nfor _ in range(m):    i, j = int(data[pos]) - 1, int(data[pos + 1]) - 1    pos += 2    seats[i], seats[j] = seats[j], seats[i] now = {name: k for k, name in enumerate(seats)}moved = [(name, k + 1, now[name] + 1) for k, name in enumerate(start) if now[name] != k]print(" ".join(seats))print(len(moved))for name, a, b in moved:    print(name, a, b)
JavaScriptmain.js · 20 行
const data = require("fs").readFileSync(0, "utf8").trim().split(/\s+/);const n = Number(data[0]);const seats = data.slice(1, 1 + n);const start = [...seats]; // 복사본. const start = seats 는 같은 배열을 가리킨다const m = Number(data[1 + n]);let pos = 2 + n;for (let k = 0; k < m; k++, pos += 2) {  const i = Number(data[pos]) - 1;  const j = Number(data[pos + 1]) - 1;  [seats[i], seats[j]] = [seats[j], seats[i]];} const now = new Map(seats.map((name, k) => [name, k]));const out = [seats.join(" ")];const moved = [];start.forEach((name, k) => {  if (now.get(name) !== k) moved.push(`${name} ${k + 1} ${now.get(name) + 1}`);});out.push(String(moved.length), ...moved);console.log(out.join("\n"));
TypeScriptmain.ts · 22 行
import { readFileSync } from "node:fs";const data: string[] = readFileSync(0, "utf8").trim().split(/\s+/);const n = Number(data[0]);const seats: string[] = data.slice(1, 1 + n);const start: string[] = [...seats]; // 복사본. const start = seats 는 같은 배열을 가리킨다const m = Number(data[1 + n]);let pos = 2 + n;for (let k = 0; k < m; k++, pos += 2) {  const i = Number(data[pos]) - 1;  const j = Number(data[pos + 1]) - 1;  [seats[i], seats[j]] = [seats[j], seats[i]];} const now = new Map<string, number>(seats.map((name, k): [string, number] => [name, k]));const out: string[] = [seats.join(" ")];const moved: string[] = [];start.forEach((name, k) => {  const at = now.get(name)!;  if (at !== k) moved.push(`${name} ${k + 1} ${at + 1}`);});out.push(String(moved.length), ...moved);console.log(out.join("\n"));
JavaMain.java · 33 行
import java.io.*;import java.util.*; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(br.readLine().trim());        String[] seats = br.readLine().trim().split(" ");        String[] start = seats.clone(); // String[] start = seats; 는 같은 배열을 가리킨다        int m = Integer.parseInt(br.readLine().trim());        for (int k = 0; k < m; k++) {            StringTokenizer st = new StringTokenizer(br.readLine());            int i = Integer.parseInt(st.nextToken()) - 1;            int j = Integer.parseInt(st.nextToken()) - 1;            String tmp = seats[i];            seats[i] = seats[j];            seats[j] = tmp;        }         Map<String, Integer> now = new HashMap<>();        for (int k = 0; k < n; k++) now.put(seats[k], k);        StringBuilder moved = new StringBuilder();        int count = 0;        for (int k = 0; k < n; k++) {            int at = now.get(start[k]);            if (at != k) {                count++;                moved.append(start[k]).append(' ').append(k + 1).append(' ').append(at + 1).append('\n');            }        }        System.out.print(String.join(" ", seats) + "\n" + count + "\n" + moved);    }}
C#Main.cs · 33 行
using System;using System.Collections.Generic;using System.Text; class Program{    static void Main()    {        int n = int.Parse(Console.ReadLine().Trim());        string[] seats = Console.ReadLine().Trim().Split(' ');        string[] start = (string[])seats.Clone(); // string[] start = seats; 는 같은 배열을 가리킨다        int m = int.Parse(Console.ReadLine().Trim());        for (int k = 0; k < m; k++)        {            string[] p = Console.ReadLine().Trim().Split(' ');            int i = int.Parse(p[0]) - 1, j = int.Parse(p[1]) - 1;            (seats[i], seats[j]) = (seats[j], seats[i]);        }         var now = new Dictionary<string, int>();        for (int k = 0; k < n; k++) now[seats[k]] = k;        var moved = new List<string>();        for (int k = 0; k < n; k++)        {            int at = now[start[k]];            if (at != k) moved.Add($"{start[k]} {k + 1} {at + 1}");        }        var sb = new StringBuilder();        sb.Append(string.Join(" ", seats)).Append('\n').Append(moved.Count).Append('\n');        foreach (string line in moved) sb.Append(line).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 33 行
#include <iostream>#include <string>#include <unordered_map>#include <utility>#include <vector> int main() {    int n, m;    std::cin >> n;    std::vector<std::string> seats(n);    for (auto& s : seats) std::cin >> s;    std::vector<std::string> start = seats; // vector는 = 가 통째로 복사한다(참조가 아니다)    std::cin >> m;    for (int k = 0; k < m; k++) {        int i, j;        std::cin >> i >> j;        std::swap(seats[i - 1], seats[j - 1]);    }     std::unordered_map<std::string, int> now;    for (int k = 0; k < n; k++) now[seats[k]] = k;    std::string out, moved;    int count = 0;    for (int k = 0; k < n; k++) out += (k ? " " : "") + seats[k];    for (int k = 0; k < n; k++) {        int at = now[start[k]];        if (at != k) {            count++;            moved += start[k] + " " + std::to_string(k + 1) + " " + std::to_string(at + 1) + "\n";        }    }    std::cout << out << "\n" << count << "\n" << moved;}
Cmain.c · 37 行
#include <stdio.h>#include <string.h> static char seats[1000][11];static char start[1000][11]; int main(void) {    int n, m;    scanf("%d", &n);    for (int k = 0; k < n; k++) scanf("%10s", seats[k]);    memcpy(start, seats, sizeof seats); /* 배열은 = 로 복사할 수 없다: 칸을 통째로 복사 */    scanf("%d", &m);    for (int k = 0; k < m; k++) {        int i, j;        char tmp[11];        scanf("%d %d", &i, &j);        i--, j--;        if (i == j) continue; /* 같은 칸끼리 strcpy 하면 겹친 복사라 안 된다 */        strcpy(tmp, seats[i]);        strcpy(seats[i], seats[j]);        strcpy(seats[j], tmp);    }     /* 처음 자리마다 지금 자리를 찾는다(n이 1000 이하라 차례로 찾아도 된다) */    static int at[1000];    int count = 0;    for (int k = 0; k < n; k++) {        for (int t = 0; t < n; t++)            if (strcmp(seats[t], start[k]) == 0) { at[k] = t; break; }        if (at[k] != k) count++;    }    for (int k = 0; k < n; k++) printf(k ? " %s" : "%s", seats[k]);    printf("\n%d\n", count);    for (int k = 0; k < n; k++)        if (at[k] != k) printf("%s %d %d\n", start[k], k + 1, at[k] + 1);    return 0;}
Craykonmain.cray · 35 行
n = 控制台.读行().转数字();seats = 控制台.读行().去空白().分割();// start = seats; 라면 같은 목록에 이름만 둘이다. 부분목록은 새 목록을 만든다start = seats.子列表(0, seats.数量);m = 控制台.读行().转数字();循环 (k = 0; k < m; k++){    p = 控制台.读数字();    i = p[0] - 1;    j = p[1] - 1;    tmp = seats[i];    seats[i] = seats[j];    seats[j] = tmp;} now = 字典();循环 (k = 0; k < n; k++){    now[seats[k]] = k;}moved = [];循环 (k = 0; k < n; k++){    at = now[start[k]];    如果 (at != k)    {        moved.添加(start[k] + " " + (k + 1) + " " + (at + 1));    }}控制台.输出(seats.连接(" "));控制台.输出(moved.数量);遍历 (line 在 moved){    控制台.输出(line);}