東京大学 情報理工学系研究科 創造情報学専攻 2024年8月実施 プログラミング
Author
vv, itsuitsuki, 祭音Myyura
Description
Answer the following questions by writing programs. The files needed for answering the questions are found in the USB flash drive. Store the programs in the USB flash drive before the examination ends.
In this problem, we represent matrices with rows and columns in various formats. The entry in the -th row and -th column in a matrix is denoted as the entry; the upper left entry of a matrix is the entry, and the entry to the right of it is the entry. We say that, for the entry, the row number is and the column number is . Here, and hold. For any matrix given in this problem, all entries are integers between and , inclusive, no row or column has more than 10 non-zero entries, and the total number of non-zero entries is at most .
Format 1 Format 1 is a number sequence that arranges the entries of a matrix in the row-major order. In the row-major order, the entries in upper rows precede those in lower rows, and entries to the left precede to the right in a row. For example, the matrix
is represented as
1, -5, 0, 0, 3, 0in Format 1.
When a number sequence is stored in a file, the concatenated string of elements separated by commas is stored. For example, the file storing a sequence of the four elements, contains the following string.
2,5,-3,0
(1) Number sequences representing matrices in Format 1 are stored in files. For each of the following matrices, find the row such that the sum of the entries is the largest, and write down on the answer sheet its row number and the sum of its entries. If there are two or more such rows, answer about one of them.
(a) The matrix with 6 rows and 4 columns stored in data1a.txt.
(b) The matrix with 100 rows and 150 columns stored in data1b.txt.
Format 2 Let be the entry of a matrix. We define Format 2 as the number sequence where the three integers and for all such that are arranged in the row-major order. For example, the matrix
is represented as
1, 1, 1, 1, 2, -5, 2, 2, 3in Format 2.
(2) Number sequences representing matrices in Format 2 are stored in files. For each of the following matrices, find the row such that the sum of the entries is the largest, and write down on the answer sheet its row number and the sum of its entries. If there are two or more such rows, answer about one of them.
(a) The matrix with 6 rows and 4 columns stored in data2a.txt.
(b) The matrix with 100 rows and 150 columns stored in data2b.txt.
(c) The matrix with rows and columns stored in data2c.txt.
Format 3 Let be the number of consecutive zeros immediately preceding the -th element in the sequence of entries of a matrix arranged in the row-major order. Let be the value of the -th element. We define Format 3 as the number sequence where the two integers and for all such that are arranged in the ascending order of . For example, the matrix
is represented as
0, 1, 0, -5, 2, 3in Format 3.
(3) Number sequences representing matrices in Format 3 are stored in files. For each of the matrices obtained by transposing the following matrices, find the row such that the sum of the entries is the largest, and write down on the answer sheet its row number and the sum of its entries. If there are two or more such rows, answer about one of them.
(a) The matrix with 4 rows and 6 columns stored in data3a.txt.
(b) The matrix with 100 rows and 150 columns stored in data3b.txt.
(c) The matrix with rows and columns stored in data3c.txt.
Questions (4)–(5): independent summary
For and , define
(4) All inputs use Format 3. For each product below, report a row with maximum sum and that sum; any tied row is acceptable.
| Case | Left matrix | Right matrix | Dimensions | Additional condition |
|---|---|---|---|---|
| (a) | data4a.txt | data4b.txt | — | |
| (b) | data4c.txt | data4d.txt | Each input has at most 1000 nonzeros. | |
| (c) | data4e.txt | data4f.txt | — |
(5) Count the axis-aligned contiguous submatrices whose entries sum to zero. There are possible positions. Inputs use Format 3.
| Case | File | ||
|---|---|---|---|
| (a) | data5a.txt | ||
| (b) | data5b.txt | ||
| (c) | data5c.txt |
The illustrative matrix has four zero-sum regions, with top-left coordinates .
题目描述
编程回答并在考试结束前把程序保存到 U 盘。本题以不同格式表示 行 列矩阵,左上角为 ,行号 ,列号 。所有矩阵元素均为 内整数;每行、每列的非零元素均不超过 10 个,总非零元素不超过 。文件中的数列都以逗号连接,无额外格式,例如 存为 2,5,-3,0。
格式 1:稠密行优先。 按从上到下、每行从左到右列出全部元素。例如
表示为 1,-5,0,0,3,0。
- 对以下格式 1 矩阵,找元素和最大的行,把行号与该行和写在答题纸上;并列任选一行。
data1a.txt:6 行 4 列。data1b.txt:100 行 150 列。
格式 2:非零坐标三元组。 对每个 ,按行优先顺序依次列 。上例表示为 1,1,1,1,2,-5,2,2,3。
- 对以下格式 2 矩阵完成同样的最大行和任务:
data2a.txt:6 行 4 列。data2b.txt:100 行 150 列。data2c.txt: 行、 列。
格式 3:零游程与非零值对。 在矩阵行优先的完整元素序列中,令 为第 个元素, 为它前面紧邻的连续 0 个数;只对 的位置按 升序列出 。上例表示为 0,1,0,-5,2,3。
- 以下文件存格式 3 的原矩阵。先将原矩阵转置,再在转置矩阵中找元素和最大的行,写出行号与行和;并列任选。
data3a.txt:原矩阵 4 行 6 列。data3b.txt:原矩阵 100 行 150 列。data3c.txt:原矩阵 行、 列。
Kai (By vv)
Save the following helper module as utils.py, and save each question’s program in the same directory as its input files.
# the utils
from pathlib import Path
def find_biggest_gyou(board: list[list[float]], r: int, c: int) -> tuple[int, float]:
best_row = 1
best_sum = float("-inf")
for i in range(r):
current_sum = sum(board[i][j] for j in range(c))
if current_sum > best_sum:
best_sum = current_sum
best_row = i + 1 # 题目要求行号从 1 开始
return best_row, best_sum
def read_from_file(path: str) -> list[int]:
"""读取以逗号分隔的整数序列文件并返回整数列表。"""
content = Path(path).read_text(encoding="utf-8").strip()
if not content:
return []
tokens = (part.strip() for part in content.replace("\n", "").replace("\r", "").split(","))
return [int(token) for token in tokens if token]
def board_init(r: int, c: int) -> list[list[float]]:
board = [[0.0 for _ in range(c)] for _ in range(r)]
return board
(1)
from pathlib import Path
import utils
def main():
# Input files are beside this script.
base_dir = Path(__file__).resolve().parent
data = utils.read_from_file(str(base_dir / 'data1a.txt'))
r = 6
c = 4
board = [[0 for _ in range(c)] for _ in range(r)]
for i in range(r):
for j in range(c):
board[i][j] = data[i * c + j]
saidaiGyou = utils.find_biggest_gyou(board, r, c)
print(saidaiGyou)
# 第二小问
data = utils.read_from_file(str(base_dir / 'data1b.txt'))
r = 100
c = 150
board = [[0 for _ in range(c)] for _ in range(r)]
for i in range(r):
for j in range(c):
board[i][j] = data[i * c + j]
saidaiGyou = utils.find_biggest_gyou(board, r, c)
print(saidaiGyou)
if __name__ == "__main__":
main()
(2)
from collections import defaultdict
from collections.abc import Iterable, Iterator
from pathlib import Path
import utils
def triple_tuple(data: list[int]) -> Iterator[tuple[int, int, int]]:
if len(data) % 3 != 0:
raise ValueError("数据长度必须是 3 的倍数。")
for idx in range(0, len(data), 3):
row, col, value = data[idx : idx + 3]
yield row, col, value
def find_max_row_sum(triples: Iterable[tuple[int, int, int]], r: int, c: int) -> tuple[int, int]:
row_sums: defaultdict[int, int] = defaultdict(int)
for row, col, value in triples:
if not (1 <= row <= r):
raise ValueError(f"行号 {row} 超出范围 1..{r}")
if not (1 <= col <= c):
raise ValueError(f"列号 {col} 超出范围 1..{c}")
row_sums[row] += value
best_row = 1
best_sum = row_sums.get(1, 0)
for row_idx in range(2, r + 1):
total = row_sums.get(row_idx, 0)
if total > best_sum:
best_row = row_idx
best_sum = total
return best_row, best_sum
def solve_case(base_dir: Path, filename: str, r: int, c: int) -> tuple[int, int]:
data = utils.read_from_file(str(base_dir/filename))
triples = triple_tuple(data)
return find_max_row_sum(triples, r, c)
def main():
base_dir = Path(__file__).resolve().parent
cases = [
("data2a.txt", 6, 4),
("data2b.txt", 100, 150),
("data2c.txt", 10**6, 10**6),
]
for filename, r, c in cases:
print(solve_case(base_dir, filename, r, c))
if __name__ == "__main__":
main()
(3)
from pathlib import Path
import utils
def solve_format3(data: list[int], r: int, c: int) -> list[int]:
if len(data) % 2 != 0:
raise ValueError("数据长度必须是 2 的倍数。")
# A row of the transposed matrix is a column of the original matrix.
transposed_row_sums = [0 for _ in range(c)]
total_cells = r * c
idx = 0
for i in range(0, len(data), 2):
zero_num = int(data[i])
value = data[i + 1]
if zero_num < 0:
raise ValueError("零段长度不能为负数。")
idx += zero_num
if idx >= total_cells:
raise ValueError("游标超出棋盘范围。")
column = idx % c
transposed_row_sums[column] += value
idx += 1
return transposed_row_sums
def solve_case(base_dir: Path, filename: str, r: int, c: int) -> tuple[int, int]:
data = utils.read_from_file(str(base_dir/filename))
row_sums = solve_format3(data, r, c)
best_row = 1
best_sum = row_sums[0]
for row_idx in range(1, c):
total = row_sums[row_idx]
if total > best_sum:
best_sum = total
best_row = row_idx + 1
return best_row, best_sum
def main():
base_dir = Path(__file__).resolve().parent
cases = [
("data3a.txt", 4, 6),
("data3b.txt", 100, 150),
("data3c.txt", 10**6, 10**6),
]
for filename, r, c in cases:
print(solve_case(base_dir, filename, r, c))
if __name__ == "__main__":
main()
(4)
Decode Format 3 into the nonzero triples and . For a fixed row , enumerate only products where both factors are nonzero, using the nonzero entries in row of as an index. For each reached column , keep the minimum, maximum, and number of these products.
If , at least one of the products is zero, so zero must also participate in both extrema. If , use only the recorded extrema. Unreached columns contribute zero to the row sum. Sum these contributions and compare all rows, including empty rows whose sum is zero. The nonzero products suffice because every omitted product has a zero factor.
With at most nonzeros per row, each nonzero in generates at most products, so the running time is . No dense product matrix is stored.
from collections import defaultdict
from itertools import groupby
from pathlib import Path
import utils
def format3_entries(data, r, c):
if len(data) % 2:
raise ValueError("Format 3 requires pairs")
position = 0
for offset in range(0, len(data), 2):
zeros, value = data[offset:offset + 2]
if zeros < 0 or value == 0:
raise ValueError("Invalid run or nonzero value")
position += zeros
if position >= r * c:
raise ValueError("Matrix index out of range")
yield position // c + 1, position % c + 1, value
position += 1
def star_max_row(x_data, y_data, l, m, n):
y_rows = defaultdict(list)
for k, j, value in format3_entries(y_data, m, n):
y_rows[k].append((j, value))
groups = iter(groupby(format3_entries(x_data, l, m), key=lambda e: e[0]))
next_group = next(groups, None)
best_row, best_sum = 1, None
for i in range(1, l + 1):
extrema = {}
if next_group is not None and next_group[0] == i:
for _, k, x in next_group[1]:
for j, y in y_rows.get(k, ()):
product = x * y
if j not in extrema:
extrema[j] = [product, product, 1]
else:
state = extrema[j]
state[0] = min(state[0], product)
state[1] = max(state[1], product)
state[2] += 1
next_group = next(groups, None)
total = 0
for low, high, count in extrema.values():
if count < m:
low, high = min(low, 0), max(high, 0)
total += low + high
if best_sum is None or total > best_sum:
best_row, best_sum = i, total
return best_row, best_sum
if __name__ == "__main__":
base = Path(__file__).resolve().parent
cases = [
("data4a.txt", "data4b.txt", 2, 4, 3),
("data4c.txt", "data4d.txt", 10**6, 10**6, 10**6),
("data4e.txt", "data4f.txt", 10**6, 10**6, 10**6),
]
for x_file, y_file, l, m, n in cases:
print(star_max_row(utils.read_from_file(base / x_file),
utils.read_from_file(base / y_file), l, m, n))
(5)
Fix the top row of a rectangle, and let be the sum in the rectangle whose left column is . There are such sums. A nonzero entry contributes to exactly when
Keep the array of these sums and the number of its zero entries. Sweep the top row downwards: remove the nonzeros in the departing row and add those in the entering row. Each changed matrix entry affects at most sums. Before and after each update, adjust the zero counter, then add that counter to the answer once all updates for the current top row are complete. This also counts rectangles containing nonzero entries that cancel, as well as completely empty rectangles.
Initially all window sums are zero; adding the first rows establishes the invariant. Removing and adding the boundary rows preserves it at each step, so the accumulated count includes every rectangle exactly once. The running time is , with in the given cases. The stored window sums require space; the active strip has at most nonzeros. The input list itself uses space. Counts and flattened matrix indices must support values up to ; Python integers do so.
Save the code from (4) as part4.py to reuse its decoder.
from collections import deque
from pathlib import Path
from part4 import format3_entries
import utils
def count_zero_rectangles(data, r, c, R, C):
if not (1 <= R <= r and 1 <= C <= c):
raise ValueError("Invalid rectangle size")
width = c - C + 1
sums = [0] * (width + 1) # Index 0 is unused.
zero_count = width
def update(column, value):
nonlocal zero_count
left = max(1, column - C + 1)
right = min(column, width)
for b in range(left, right + 1):
old = sums[b]
new = old + value
zero_count += (new == 0) - (old == 0)
sums[b] = new
entries = iter(format3_entries(data, r, c))
current = next(entries, None)
active = deque()
answer = 0
for top in range(1, r - R + 2):
while active and active[0][0] < top:
_, column, value = active.popleft()
update(column, -value)
while current is not None and current[0] < top + R:
active.append(current)
_, column, value = current
update(column, value)
current = next(entries, None)
answer += zero_count
return answer
if __name__ == "__main__":
base = Path(__file__).resolve().parent
cases = [("data5a.txt", 8, 6, 2, 3),
("data5b.txt", 10**6, 10**6, 10, 10),
("data5c.txt", 10**6, 10**6, 100, 100)]
for filename, r, c, R, C in cases:
print(count_zero_rectangles(utils.read_from_file(base / filename), r, c, R, C))