{ }codelper
嵌套循环二维列表P0234

两人都有空的天数表

为了定聚会日期,问了 n 个人接下来 m 天里哪几天有空。
第一行给出人数 n 和天数 m,用一个空格分开。
接下来 n 行从 1 号开始依次给出每个人的回答,是长度为 m 的字符串。
字符串的第 k 个字符为大写 O 表示这个人第 k 天有空,为大写 X 表示没空。
两个人 i 和 j 共同有空的天数,是两人都为 O 的天数。
从第 1 行到第 n 行,第 i 行输出 j = 1 到 n 时 i 和 j 共同有空的天数,用单个空格分开。
i 和 j 相同时,写这个人自己有空的天数(O 的个数)。
最后一行输出不同的两个人中共同有空天数最多的一对的编号 i 和 j(i < j),用一个空格分开。
如果这样的对有多个,输出 i 最小的;仍有多个时输出 j 最小的。
如果所有的对共同有空天数都是 0,输出 1 2。

输入
2 ≤ n ≤ 100,1 ≤ m ≤ 100,回答是只由大写 O 和 X 组成的长度为 m 的字符串
输出
n 行:n × n 的表 / 最后一行:共同有空天数最多的两人的编号
样例 1 · stdin
4 5
OOXOX
XOOOX
OOOOO
XXXXO
stdout
3 2 3 0
2 3 3 0
3 3 5 1
0 0 1 1
1 3
样例 2 · stdin
2 3
OXO
XOX
stdout
2 0
0 1
1 2
main.py
输入(stdin)

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

$ 就绪

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

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

这是三重循环:人 i、人 j、日 k。
循环头:Python for i in range(n):,JS/TS/Java/C#/C/C++ for (int i = 0; i < n; i++)(JS/TS 用 let),Craykon 循环 (i = 0; i < n; i++)。
最常见的错误是把计数变量 count = 0 放在 j 循环外面。
这样换了一对也不会归零,前面几对的数会累加起来。
要在被计数的对象改变的地方,也就是 j 循环的里面紧接着归零。
C 语言如果在函数开头先声明好循环变量,又把内层 for 的初始化留空(for (; j < n; j++)),j 就不会重新开始,只检查了第一个人。
要像 for (int j = i + 1; ...) 这样每次重新设定。
建表的方法各语言也不同。
Python [[0] * n] * n 是同一行被指向了 n 次,改一个格子,所有行的同一格都会变,要用 [[0] * n for _ in range(n)] 每行新建。
JS/TS 写成 new Array(n).fill(new Array(n).fill(0)) 也会出同样的问题,要用 Array.from({ length: n }, () => new Array(n).fill(0))。
Java new int[n][n]、C# new int[n, n]、C int common[100][100]、C++ std::vector<std::vector<int>>(n, std::vector<int>(n)) 的每个格子都是分开创建的。
Craykon 用循环每行放入一个 新列表(n, 0)。
读字符:Python、JS、TS、C#、C、C++、Craykon 用 rows[i][k],Java 用 rows[i].charAt(k)。
(i, j) 和 (j, i) 的值相同,只数 j ≥ i 并同时存进两个格子,工作量大约减半。
找最多的一对时,j 从 i + 1 开始,才不会选到自己和自己的格子(对角线);按顺序遍历、只在 > 时替换,相同时才会保留前面的一对。
输出编号时要把数组下标加 1。

Pythonmain.py · 23 行
n, m = map(int, input().split())rows = [input() for _ in range(n)] # common[i][j]: i와 j가 둘 다 비는 날의 수. (i, j)와 (j, i)는 같으니 j >= i만 세고 거울처럼 채운다common = [[0] * n for _ in range(n)]for i in range(n):    for j in range(i, n):        count = 0  # 쌍마다 새로 센다        for k in range(m):            if rows[i][k] == "O" and rows[j][k] == "O":                count += 1        common[i][j] = common[j][i] = count for row in common:    print(" ".join(map(str, row))) # 서로 다른 두 사람만: j는 i + 1부터. 차례대로 돌며 >로 바꾸면 같을 때 앞의 쌍이 남는다best_i, best_j = 0, 1for i in range(n):    for j in range(i + 1, n):        if common[i][j] > common[best_i][best_j]:            best_i, best_j = i, jprint(best_i + 1, best_j + 1)
JavaScriptmain.js · 29 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [n, m] = lines[0].trim().split(/\s+/).map(Number);const rows = lines.slice(1, 1 + n).map((s) => s.trim()); // common[i][j]: i와 j가 둘 다 비는 날의 수. j >= i만 세고 거울처럼 채운다const common = Array.from({ length: n }, () => new Array(n).fill(0));for (let i = 0; i < n; i++) {  for (let j = i; j < n; j++) {    let count = 0; // 쌍마다 새로 센다    for (let k = 0; k < m; k++) {      if (rows[i][k] === "O" && rows[j][k] === "O") count++;    }    common[i][j] = common[j][i] = count;  }} const out = common.map((row) => row.join(" "));let bi = 0;let bj = 1;for (let i = 0; i < n; i++) {  for (let j = i + 1; j < n; j++) {    if (common[i][j] > common[bi][bj]) {      bi = i;      bj = j;    }  }}out.push(`${bi + 1} ${bj + 1}`);console.log(out.join("\n"));
TypeScriptmain.ts · 30 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const [n, m] = lines[0].trim().split(/\s+/).map(Number);const rows: string[] = lines.slice(1, 1 + n).map((s) => s.trim()); // common[i][j]: i와 j가 둘 다 비는 날의 수. j >= i만 세고 거울처럼 채운다const common: number[][] = Array.from({ length: n }, () => new Array<number>(n).fill(0));for (let i = 0; i < n; i++) {  for (let j = i; j < n; j++) {    let count = 0; // 쌍마다 새로 센다    for (let k = 0; k < m; k++) {      if (rows[i][k] === "O" && rows[j][k] === "O") count++;    }    common[i][j] = common[j][i] = count;  }} const out: string[] = common.map((row) => row.join(" "));let bi = 0;let bj = 1;for (let i = 0; i < n; i++) {  for (let j = i + 1; j < n; j++) {    if (common[i][j] > common[bi][bj]) {      bi = i;      bj = j;    }  }}out.push(`${bi + 1} ${bj + 1}`);console.log(out.join("\n"));
JavaMain.java · 46 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringTokenizer; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        StringTokenizer st = new StringTokenizer(in.readLine());        int n = Integer.parseInt(st.nextToken()), m = Integer.parseInt(st.nextToken());        String[] rows = new String[n];        for (int i = 0; i < n; i++) rows[i] = in.readLine().trim();         // common[i][j]: i와 j가 둘 다 비는 날의 수. j >= i만 세고 거울처럼 채운다        int[][] common = new int[n][n];        for (int i = 0; i < n; i++) {            for (int j = i; j < n; j++) {                int count = 0; // 쌍마다 새로 센다                for (int k = 0; k < m; k++) {                    if (rows[i].charAt(k) == 'O' && rows[j].charAt(k) == 'O') count++;                }                common[i][j] = common[j][i] = count;            }        }         StringBuilder out = new StringBuilder();        for (int i = 0; i < n; i++) {            for (int j = 0; j < n; j++) {                if (j > 0) out.append(' ');                out.append(common[i][j]);            }            out.append('\n');        }        int bi = 0, bj = 1;        for (int i = 0; i < n; i++) {            for (int j = i + 1; j < n; j++) {                if (common[i][j] > common[bi][bj]) {                    bi = i;                    bj = j;                }            }        }        out.append(bi + 1).append(' ').append(bj + 1).append('\n');        System.out.print(out);    }}
C#Main.cs · 53 行
using System;using System.Text; class Program{    static void Main()    {        string[] nm = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int n = int.Parse(nm[0]), m = int.Parse(nm[1]);        var rows = new string[n];        for (int i = 0; i < n; i++) rows[i] = Console.ReadLine().Trim();         // common[i, j]: i와 j가 둘 다 비는 날의 수. j >= i만 세고 거울처럼 채운다        var common = new int[n, n];        for (int i = 0; i < n; i++)        {            for (int j = i; j < n; j++)            {                int count = 0; // 쌍마다 새로 센다                for (int k = 0; k < m; k++)                {                    if (rows[i][k] == 'O' && rows[j][k] == 'O') count++;                }                common[i, j] = common[j, i] = count;            }        }         var out_ = new StringBuilder();        for (int i = 0; i < n; i++)        {            for (int j = 0; j < n; j++)            {                if (j > 0) out_.Append(' ');                out_.Append(common[i, j]);            }            out_.Append('\n');        }        int bi = 0, bj = 1;        for (int i = 0; i < n; i++)        {            for (int j = i + 1; j < n; j++)            {                if (common[i, j] > common[bi, bj])                {                    bi = i;                    bj = j;                }            }        }        out_.Append(bi + 1).Append(' ').Append(bj + 1).Append('\n');        Console.Write(out_);    }}
C++main.cpp · 38 行
#include <iostream>#include <string>#include <vector> int main() {    std::ios::sync_with_stdio(false);    int n, m;    std::cin >> n >> m;    std::vector<std::string> rows(n);    for (auto& r : rows) std::cin >> r;     // common[i][j]: i와 j가 둘 다 비는 날의 수. j >= i만 세고 거울처럼 채운다    std::vector<std::vector<int>> common(n, std::vector<int>(n, 0));    for (int i = 0; i < n; i++) {        for (int j = i; j < n; j++) {            int count = 0; // 쌍마다 새로 센다            for (int k = 0; k < m; k++) {                if (rows[i][k] == 'O' && rows[j][k] == 'O') count++;            }            common[i][j] = common[j][i] = count;        }    }     for (int i = 0; i < n; i++) {        for (int j = 0; j < n; j++) std::cout << (j ? " " : "") << common[i][j];        std::cout << '\n';    }    int bi = 0, bj = 1;    for (int i = 0; i < n; i++) {        for (int j = i + 1; j < n; j++) {            if (common[i][j] > common[bi][bj]) {                bi = i;                bj = j;            }        }    }    std::cout << bi + 1 << ' ' << bj + 1 << '\n';}
Cmain.c · 37 行
#include <stdio.h> static char rows[100][101];static int common[100][100]; int main(void) {    int n, m;    scanf("%d %d", &n, &m);    for (int i = 0; i < n; i++) scanf("%100s", rows[i]);     /* common[i][j]: i와 j가 둘 다 비는 날의 수. j >= i만 세고 거울처럼 채운다 */    for (int i = 0; i < n; i++) {        for (int j = i; j < n; j++) {            int count = 0; /* 쌍마다 새로 센다 */            for (int k = 0; k < m; k++) {                if (rows[i][k] == 'O' && rows[j][k] == 'O') count++;            }            common[i][j] = common[j][i] = count;        }    }     for (int i = 0; i < n; i++) {        for (int j = 0; j < n; j++) printf(j ? " %d" : "%d", common[i][j]);        printf("\n");    }    int bi = 0, bj = 1;    for (int i = 0; i < n; i++) {        for (int j = i + 1; j < n; j++) {            if (common[i][j] > common[bi][bj]) {                bi = i;                bj = j;            }        }    }    printf("%d %d\n", bi + 1, bj + 1);    return 0;}
Craykonmain.cray · 50 行
nm = 控制台.读数字();n = nm[0];m = nm[1];rows = [];循环 (i = 0; i < n; i++){    rows.添加(控制台.读行().去空白());} // common[i][j]: i와 j가 둘 다 비는 날의 수. j >= i만 세고 거울처럼 채운다common = [];循环 (i = 0; i < n; i++){    common.添加(新列表(n, 0));}循环 (i = 0; i < n; i++){    循环 (j = i; j < n; j++)    {        count = 0; // 쌍마다 새로 센다        循环 (k = 0; k < m; k++)        {            如果 (rows[i][k] == "O" && rows[j][k] == "O")            {                count++;            }        }        common[i][j] = count;        common[j][i] = count;    }} 循环 (i = 0; i < n; i++){    控制台.输出(common[i].连接(" "));}bi = 0;bj = 1;循环 (i = 0; i < n; i++){    循环 (j = i + 1; j < n; j++)    {        如果 (common[i][j] > common[bi][bj])        {            bi = i;            bj = j;        }    }}控制台.输出(bi + 1 + " " + (bj + 1));