В клетки таблицы 8x8 записаны числа 1 и -1 так, чт...
Создано: 2 октября 2025 г.
Отвечено с использованием GPT-5 Thinking от Chat01
Создано: 2 октября 2025 г.
Отвечено с использованием GPT-5 Thinking от Chat01
В клетки таблицы 8x8 записаны числа 1 и -1 так, что в каждой строке, в каждом столбце и на каждой диагонали (в частности, в угловых клетках) произведения чисел равны . Какое максимальное число минус единиц при этом возможно?
python# Let's model the 8x8 grid constraints over GF(2). # Variables x[i][j] in {0,1} where 1 indicates -1, 0 indicates +1. # Constraints: For each row, sum_j x[i][j] == 0 mod 2 (even -1 count). # For each column, sum_i x[i][j] == 0 mod 2. # For each NW-SE diagonal (i-j = const), sum == 0 mod 2. # For each NE-SW diagonal (i+j = const), sum == 0 mod 2. # Build matrix A over GF(2) with rows as constraints and columns as variables (64). import itertools import random n=8 var_index = {(i,j): i*n+j for i in range(n) for j in range(n)} A = [] # Row constraints for i in range(n): row = [0]* (n*n) for j in range(n): row[var_index[(i,j)]] = 1 A.append(row) # Column constraints for j in range(n): row = [0]* (n*n) for i in range(n): row[var_index[(i,j)]] = 1 A.append(row) # NW-SE diagonals (i-j = d from -(n- (46, 64)
python# Gaussian elimination over GF(2) def gf2_rank(mat): A = [row[:] for row in mat] m = len(A) n = len(A[0]) if m>0 else 0 rank = 0 col = 0 pivot_cols=[] for r in range(m): # find pivot in col >= current col # move through columns until find a column with a 1 at / below row r found = False while col < n: pivot = None for i in range(r, m): if A[i][col] == 1: pivot = i break if pivot is None: col += 1 else: # swap rows r and pivot A[r], A[pivot] = A[pivot], A[r] # eliminate below and above for i in range(m): if i != r and A[i][col] == 1: # XOR row r into row i A[i] = [(A[i][j] ^ A[r][j]) for j in range(n)] rank += 1 pivot_cols.append(col) col += 1 found = True break if not found: break return rank, pivot_cols rank, pivot_cols = gf2_rank(A) rank, 64-rank (39, 25)
python# Let's compute a basis for the nullspace. def gf2_nullspace_basis(A): # Compute reduced row echelon form and track pivot columns m = len(A) n = len(A[0]) if m>0 else 0 # Augment with identity? We'll use standard method to derive basis. # We'll perform elimination to get pivot structure, then for each free variable e_f, solve for basic vars. A_red = [row[:] for row in A] rank = 0 col = 0 pivot_row_for_col = [-1]*n for r in range(m): pivot = None while col < n: # find pivot row pr = None for i in range(r, m): if A_red[i][col] == 1: pr = i break if pr is None: col += 1 else: # swap rows A_red[r], A_red[pr] = A_red[pr], A_red[r] # eliminate other rows for i in range(m): if i != r and A_red[i][col] == 1: A_red[i] = [(A_red[i][j] ^ A_red[r][j]) for j in range(n)] pivot_row_for_col[col] = r rank += 1 col += 1 break if col >= n: break pivot_cols = [i for i in range(n) if pivot_row_for_col[i] != -1] free_cols = [i for i in range(n) if pivot_row_for_col[i] == -1] basis = [] for f in free_cols: vec = [0]*n vec[f] = 1 # For each pivot column p, determine v[p] to satisfy A_red[pivot_row_for_col[p]] * v = 0 for p in pivot_cols: r = pivot_row_for_col[p] # the equation is sum_j A_red[r][j]*v[j] = 0 mod 2 # So v[p] = sum_{j!=p} A_red[r][j]*v[j] (since A[r][p]=1) s = 0 for j in range(n): if j != p and A_red[r][j] and vec[j]: s ^= 1 vec[p] = s # since 1*v[p] + sum = 0 => v[p] = sum basis.append(vec) return basis, free_cols, pivot_cols basis, free_cols, pivot_cols = gf2_nullspace_basis(A) len(basis), len(free_cols), len(pivot_cols) (25, 25, 39)
pythonimport random, math, time import numpy as np # Convert basis to numpy array shape (n, k) with bits 0/1 B = np.array(basis, dtype=np.uint8).T # shape (64,25) def weight_from_y(y): # x = B @ y mod 2; compute weight x = (B @ y) % 2 return int(x.sum()), x def hill_climb(iterations=2000, restarts=50): best_w = 0 best_x = None best_y = None n_vars = B.shape[1] for r in range(restarts): y = np.random.randint(0,2,size=(n_vars,), dtype=np.uint8) w, x = weight_from_y(y) improved = True while improved: improved = False # try single-bit flips that improve indices = list(range(n_vars)) random.shuffle(indices) for i in indices: # toggle y[i] y[i] ^= 1 w2, x2 = weight_from_y(y) if w2 > w: w, x = w2, x2 improved = True else: # revert y[i] ^= 1 # Optionally try pair flips? if w > best_w: best_w = w best_x = x.copy() best_y = y.copy() return best_w, best_x, best_y best_w, best_x, best_y = hill_climb(iterations=2000, restarts=200) best_w 44
pythondef hill_climb_pairs(restarts=200, max_no_improve=1000): best_w = 0 best_x = None best_y = None k = B.shape[1] for r in range(restarts): y = np.random.randint(0,2,size=(k,), dtype=np.uint8) w, x = weight_from_y(y) no_improve = 0 while no_improve < max_no_improve: improved = False # single bit flips for i in range(k): y[i] ^= 1 w2, x2 = weight_from_y(y) if w2 > w: w, x = w2, x2 improved = True break else: y[i] ^= 1 if improved: no_improve = 0 continue # try random pair flip i, j = random.sample(range(k), 2) y[i] ^= 1; y[j] ^= 1 w2, x2
pythonimport numpy as np, random n=8 # Build A again var_index = {(i,j): i*n+j for i in range(n) for j in range(n)} A = [] for i in range(n): row = [0]* (n*n) for j in range(n): row[var_index[(i,j)]] = 1 A.append(row) for j in range(n): row = [0]* (n*n) for i in range(n): row[var_index[(i,j)]] = 1 A.append(row) for d in range(-(n-1), n): row = [0]* (n*n) for i in range(n): j = i - d if 0 <= j < n: row[var_index[(i,j)]] = 1 A.append(row) for s in range(2*(n-1)+1): row = [0]* (n*n) for i in range(n): j = s - i if 0 <= j < n: row[var_index[( 46
pythonfor loops in [100000, 200000]: best_w_local = 0 for t in range(loops): y = np.random.randint(0,2,size=(k,),dtype=np.uint8) w = int(((B @ y) % 2).sum()) if w > best_w: best_w = w print("done", loops, "current best", best_w)
pythonbest_w = 0 best_x = None best_y = None for t in range(500000): y = np.random.randint(0,2,size=(k,),dtype=np.uint8) x = (B @ y) % 2 w = int(x.sum()) if w > best_w: best_w = w best_x = x.copy() best_y = y.copy() # print whenever improved #print("improved", best_w) best_w 48
pythonfor t in range(1000000): y = np.random.randint(0,2,size=(k,),dtype=np.uint8) w = int(((B @ y) % 2).sum()) if w > best_w: best_w = w #print("new", best_w) best_w 48
python# Check whether every 2x2 block has even parity in the currently found best_x def random_solution(): k = B.shape[1] y = np.random.randint(0,2,size=(k,),dtype=np.uint8) return (B @ y) % 2 x = best_x.reshape(8,8) def check_2x2_even(x): n=8 for i in range(n-1): for j in range(n-1): s = int(x[i,j]+x[i+1,j]+x[i,j+1]+x[i+1,j+1]) % 2 if s==1: return False return True check_2x2_even(x), best_w (False, 48)
python# analyze parity in 4 color classes by (i%2, j%2) def class_parities(x): par = {(a,b):0 for a in [0,1] for b in [0,1]} for i in range(8): for j in range(8): if x[i,j]==1: par[(i%2,j%2)] ^= 1 return par class_parities(x), x.sum() ({(0, 0): 0, (0, 1): 0, (1, 0): 0, (1, 1): 0}, 48)
python# Get positions of +1 (x==0) pos_plus = [(i,j) for i in range(8) for j in range(8) if x[i,j]==0] len(pos_plus), pos_plus[:10] (16, [(0, 0), (0, 7), (1, 2), (1, 6), (2, 0), (2, 5), (3, 0), (3, 1), (4, 2), (4, 3)])
pythonpos_plus [(0, 0), (0, 7), (1, 2), (1, 6), (2, 0), (2, 5), (3, 0), (3, 1), (4, 2), (4, 3), (5, 3), (5, 5), (6, 1), (6, 6), (7, 0), (7, 7)]
python# Verify one plus per odd NW-SE diagonal and per even-s antidiagonal odd_d = [d for d in range(-(n-1),n) if abs(d)%2==1] even_s = [s for s in range(2*(n-1)+1) if s%2==0] def diag_cells_d(d): return [(i,i-d) for i in range(n) if 0<=i-d<n] def diag_cells_s(s): return [(i,s-i) for i in range(n) if 0<=s-i<n] plus_set = set(pos_plus) nw_ok = all(any((i,j) in plus_set for (i,j) in diag_cells_d(d)) for d in odd_d) ne_ok = all(any((i,j) in plus_set for (i,j) in diag_cells_s(s)) for s in even_s) nw_ok, ne_ok (True, True)
pythonrow_plus = [sum(1 for j in range(8) if x[i,j]==0) for i in range(8)] col_plus = [sum(1 for i in range(8) if x[i,j]==0) for j in range(8)] row_plus, col_plus ([2, 2, 2, 2, 2, 2, 2, 2], [4, 2, 2, 2, 0, 2, 2, 2])
python# Count plus per each odd NW-SE diagonal odd_d = [d for d in range(-7,8) if abs(d)%2==1] nw_counts = {d: sum((i,j) in plus_set for (i,j) in diag_cells_d(d)) for d in odd_d} even_s = [s for s in range(0,15) if s%2==0] ne_counts = {s: sum((i,j) in plus_set for (i,j) in diag_cells_s(s)) for s in even_s} nw_counts, ne_counts ({-7: 1, -5: 1, -3: 1, -1: 1, 1: 1, 3: 1, 5: 1, 7: 1}, {0: 1, 2: 1, 4: 1, 6: 1, 8: 1, 10: 1, 12: 1, 14: 1})
Ответ: 48.
Доказательство верхней оценки.
Покрасим доску 8×8 в шахматные цвета. Рассмотрим все диагонали в обоих направлениях.
Диагонали вида (↘↖). Из них ровно 8 диагоналей имеют нечётную длину (сумма чётна: 0,2,4,6,8,10,12,14). Каждая такая диагональ целиком состоит из клеток одного цвета (скажем, «белых»). Так как произведение чисел на диагонали равно 1, а длина диагонали нечётна, на каждой такой диагонали обязательно есть хотя бы одна . Эти 8 диагоналей попарно не пересекаются, значит требуется как минимум 8 белых .
Диагонали вида (↗↙). Ровно 8 из них имеют нечётную длину (когда нечётно). Каждая такая диагональ целиком состоит из клеток противоположного цвета (скажем, «чёрных»). По той же причине на каждой такой диагонали должна быть хотя бы одна . Эти 8 диагоналей также попарно не пересекаются, значит требуется как минимум 8 чёрных .
Заметим, что клетка не может одновременно лежать на нечётной диагонали обоих направлений (из нечётно следует нечётно), поэтому белые и чёрные «обязательные» не пересекаются. Итого нужно минимум 16 клеток с . Следовательно, число не превосходит .
Построение (достижимость 48).
Ниже одна из раскладок, где ровно 16 клеток равны , а остальные — ; при этом в каждой строке, столбце и на каждой диагонали произведение равно .
Обозначим = , = .
text+ - - - - - - + - - + - - - + - + - - - - + - - + + - - - - - - - - + + - - - - - - - + - + - - - + - - - - + - + - - - - - - +
(Координаты в (строка, столбец), 1-индексация: (1,1), (1,8), (2,3), (2,7), (3,1), (3,6), (4,1), (4,2), (5,3), (5,4), (6,4), (6,6), (7,2), (7,7), (8,1), (8,8).)
В этой конфигурации в каждой нечётной диагонали обоих направлений стоит ровно одна , а в строках и столбцах число чётно, поэтому все требования выполнены. Значит, максимум действительно равен 48.
На доске 5 x 5 в каждой клетке сидит жук. Все жуки одновременно переползли на соседнюю по стороне клетку. Какое наибольшее количество пустых клеток могло при этом остаться?
Ответ: 16.
Идея: после «переползания» занятыми окажутся только те клетки, в которые кто-то переполз. Хотим минимизировать число таких клеток (тогда пустых будет ). Каждому жуку надо переползти в соседнюю по стороне клетку, значит каждая исходная клетка должна иметь соседа из . Кроме того, каждая клетка из тоже должна иметь соседа из (жук, сидевший на ней, тоже обязан переползти). То есть — это множество тотального доминирования на решётке .
По симметрии в нижних двух строках тоже не меньше 3 клеток из .
Клетки средней строки (третья строка) не могут доминироваться сверху из первой или снизу из пятой строки, значит для их доминирования нужны клетки из строк 2–4. Легко проверить, что двумя клетками в строках 2–4 всю третью строку не покрыть, не нарушив «соседство внутри » (крайние клетки (3,1) и (3,5) неизбежно «рвут» пару). Поэтому в строках 2–4 нужно как минимум 3 клетки из .
Из (1)–(3) во всех случаях получается . (Интуитивно: по 3 «опоры» сверху и снизу, и ещё как минимум 3 в «поясе» 2–4.)
Покажем расстановку из 9 занятых клеток , куда все могут переползти за один шаг:
Возьмём все клетки второй строки и ещё четыре клетки внизу:
План переползания (везде один шаг по стороне):
Легко проверить, что каждая клетка имеет соседнюю из , и каждая клетка имеет соседа в (напр., и — соседи, — сосед с и т.д.).
Значит минимально возможное число занятых клеток после переползания — 9, а максимально возможное число пустых клеток — .