Реши задачу на c++ Задача K. Лодка Ограничение по ...
생성일: 2025년 12월 6일
답변에 사용된 모델 GPT-5.1 Thinking by Chat01
생성일: 2025년 12월 6일
답변에 사용된 모델 GPT-5.1 Thinking by Chat01
Реши задачу на c++ Задача K. Лодка
Ограничение по времени: 1 секунда
Ограничение по памяти: 256 мегабайт
Река отделяет Верхний Тагил от Нижнего Тагила. Для транспортировки людей между этими
двумя городами предусмотрена двухместная лодка (лодка, которая может перевозить не более двух
человек) с определённой грузоподъемностью. Этой лодкой должен управлять как минимум один
человек, т.е. она не может двигаться через реку без пассажиров.
Национальный фестиваль Тагила запланирован в Верхнем Тагиле. Все жители Нижнего Тагила
хотят участвовать в этом празднике и нуждаются в том, чтобы как можно быстрее добраться до
Верхнего Тагила.
Ваша задача — помочь им добраться до Верхнего Тагила с минимальным количеством поездок
на лодке через реку.
Формат входных данных
Первая строка входных данных содержит два целых числа n и w, где n — количество жителей
НижнегоТагила(1 ⩽ n ⩽ 1000),аw —максимальныйвес,которыйможетнестилодка(1 ⩽ w ⩽ 106).
Следующая строка содержит n целых чисел, разделённых пробелами, описывающих веса жителей
Нижнего Тагила. Все веса — положительные целые числа, не превышающие 106
.
Формат выходных данных
Если невозможно перевезти всех жителей Нижнего Тагила, выведите в выходных данных одну
строку, содержащую “-1”. В противном случае выведите минимальное количество раз, которое лодка
должна совершить поездки между Нижним Тагилом и Верхним Тагилом (в обе стороны), чтобы
перевезти всех жителей Нижнего Тагила в Верхний Тагил.
Примеры
стандартный ввод стандартный вывод
3 7
1 3 4
3 4
2 3 4
3
-1
pythondef exists_pair_leq_w(weights,w): n=len(weights) for i in range(n): for j in range(i+1,n): if weights[i]+weights[j]<=w: return True return False def test_feasibility(trials=1000,max_n=6,max_w=10): bad=[] for _ in range(trials): n=random.randint(1,max_n) w_cap=random.randint(1,max_w) weights=[random.randint(1,max_w) for _ in range(n)] bf=min_trips_bruteforce(weights,w_cap) cond1=not any(x>w_cap for x in weights) cond2=(n==1) or exists_pair_leq_w(weights,w_cap) # my candidate feasibility rule: feas_rule = cond1 and cond2 if (bf is None) != (not feas_rule): bad.append((weights,w_cap,bf,feas_rule)) if len(bad)>=10: break (0, [])
pythondef unconstrained_min(n): if n==1: return 1 else: return 2*n-3 for n in range(1,8): # choose huge capacity weights=list(range(1,n+1)) w_cap=sum(weights)+10 print(n, min_trips_bruteforce(weights,w_cap), unconstrained_min(n))
pythontry: import networkx as nx print("has networkx", nx.__version__) except Exception as e: print("no networkx", e)
pythondef compatibility_graph(weights,w_cap): n=len(weights) G=nx.Graph() G.add_nodes_from(range(n)) for i in range(n): for j in range(i+1,n): if weights[i]+weights[j]<=w_cap: G.add_edge(i,j) return G def analyze_random(trials=2000,max_n=7,max_w=10,seed=0): random.seed(seed) rows=[] for _ in range(trials): n=random.randint(1,max_n) w_cap=random.randint(1,max_w) weights=[random.randint(1,max_w) for _ in range(n)] bf=min_trips_bruteforce(weights,w_cap) if bf is None: continue if n==1: base=1 else: base=2*n-3 diff=bf-base G=compatibility_graph(weights,w_cap) degs=[G.degree(i) for i in range(n)] n_loners=sum(1 for d in degs if d==0) comps=list(nx.connected_components(G)) comp_sizes=[len(c) for c in comps] rows.append(dict( n=n,w=w_cap,weights=weights,bf=bf,diff=diff, n_loners=n_loners, n_comps=len(comps), comp_sizes=sorted(comp_sizes) )) return rows rows=analyze_random(5000) len(rows), sorted(set(r['diff'] for r in rows))[:20] (1224, [0, 2, 4, 6, 8, 10])
pythonfrom collections import Counter cnt_diff=Counter(r['diff'] for r in rows) cnt_diff, sum(cnt_diff.values()) (Counter({0: 801, 2: 254, 4: 106, 6: 45, 8: 16, 10: 2}), 1224)
pythonby_diff={} for r in rows: by_diff.setdefault(r['diff'],[]).append(r) for d in sorted(by_diff): lon_counts=Counter(r['n_loners'] for r in by_diff[d]) print("diff",d,"loners->count",lon_counts)
pythonfor lon in range(0,6): diffs=set(r['diff'] for r in rows if r['n_loners']==lon) print("loners",lon,"diffs",diffs)
pythonprint("bf[3,5,8,8],w=10:", min_trips_bruteforce([3,5,8,8],10))
pythondef formula1(weights,w_cap): n=len(weights) # feasibility if any(x>w_cap for x in weights): return None if n>1: ok=False for i in range(n): for j in range(i+1,n): if weights[i]+weights[j]<=w_cap: ok=True break if ok: break if not ok: return None if n==1: return 1 # compute loners n=len(weights) L=0 for i in range(n): if all((i==j) or (weights[i]+weights[j]>w_cap) for j in range(n)): L+=1 return (2*n-3)+2*L def test_formula1(max_n=7,max_w=10): bad=[] for n in range(1,max_n+1): for w_cap in range(1,max_w+1): # generate all multi-sets of weights from 1..max_w? that's huge (max_w^n). # Instead random sample. for _ in range(200): weights=[random.randint(1,max_w) for __ in range(n)] bf=min_trips_bruteforce(weights,w_cap) f=formula1(weights,w_cap) if (bf is None) != (f is None): bad.append(("feas_mismatch",n,w_cap,weights,bf,f)) if len(bad)>5: return bad if bf is not None and bf!=f: bad.append(("value_mismatch",n,w_cap,weights,bf,f)) if len(bad)>5: return bad return bad bad=test_formula1() len(bad), bad[:5] (0, [])
pythonfrom itertools import combinations_with_replacement def exhaustive_check(max_n=6,max_w=10,weight_max=10): bad=[] for n in range1:=range(1,max_n+1): for w_cap in range(1,max_w+1): for weights in combinations_with_replacement(range(1,weight_max+1), n): weights=list(weights) bf=min_trips_bruteforce(weights,w_cap) f=formula1(weights,w_cap) if (bf is None) != (f is None): bad.append(("feas_mismatch",n,w_cap,weights,bf,f)) if len(bad)>10: return bad if bf is not None and bf!=f: bad.append(("value_mismatch",n,w_cap,weights,bf,f)) if len(bad)>10: return bad
pythonfrom itertools import combinations_with_replacement def exhaustive_check(max_n=6,max_w=8,weight_max=8): bad=[] for n in range(1,max_n+1): for w_cap in range(1,max_w+1): for weights in combinations_with_replacement(range(1,weight_max+1), n): weights=list(weights) bf=min_trips_bruteforce(weights,w_cap) f=formula1(weights,w_cap) if (bf is None) != (f is None): bad.append(("feas_mismatch",n,w_cap,weights,bf,f)) if len(bad)>10: return bad if bf is not None and bf!=f: bad.append(("value_mismatch",n,w_cap,weights,bf,f)) if len(bad)>10: return bad return bad bad=exhaustive_check() len(bad), bad[:5] (0, [])
pythonrows2=[] for _ in range(2000): n=random.randint(1,7) w_cap=random.randint(1,10) weights=[random.randint(1,10) for __ in range(n)] bf=min_trips_bruteforce(weights,w_cap) if bf is None: continue if n==1: base=1 else: base=2*n-3 L=sum(1 for i in range(n) if all((i==j) or (weights[i]+weights[j]>w_cap) for j in range(n))) rows2.append(dict(n=n,w=w_cap,weights=weights,bf=bf,base=base,L=L,diff=bf-base,f=formula1(weights,w_cap))) from collections import Counter print("diff vs L:", {L:set(r['diff'] for r in rows2 if r['L']==L) for L in range(6)}) print("mismatch count:", sum(1 for r in rows2 if r['bf']!=r['f']))
pythonprint(textwrap.indent(inspect.getsource(formula1)," "))
pythonexamples=[r for r in rows2 if r['L']==1 and r['diff']==0][:10] len(examples), examples[:3] (10, [{'n': 1, 'w': 6, 'weights': [1], 'bf': 1, 'base': 1, 'L': 1, 'diff': 0, 'f': 1}, {'n': 1, 'w': 5, 'weights': [2], 'bf': 1, 'base': 1, 'L': 1, 'diff': 0, 'f': 1}, {'n': 1, 'w': 4, 'weights': [4], 'bf': 1, 'base': 1, 'L': 1, 'diff': 0, 'f': 1}])
pythonfor L in range(1,5): diffs=set(r['diff'] for r in rows2 if r['L']==L and r['n']>1) print("n>1, L",L,"diffs",diffs)
pythonimport time, random, math def alg(weights,w): n=len(weights) if any(x>w for x in weights): return None canPair=[False]*n hasPair=False for i in range(n): wi=weights[i] for j in range(i+1,n): if wi + weights[j] <= w: hasPair=True canPair[i]=canPair[j]=True if n>1 and not hasPair: return None L=sum(1 for b in canPair if not b) return (2*n-3)+2*L for n in [200,500,1000]: w=1_000_000 weights=[random.randint(1,w) for _ in range(n)] t0=time.time() ans=alg(weights,w) t1=time.time() print(n,"time",t1-t0,"ans",ans)
Сделаем сразу вывод: решение на удивление простое — нужно всего лишь посчитать, сколько людей вообще ни с кем не могут сидеть в лодке одновременно.
Обозначения:
n — число жителей.w — грузоподъёмность лодки.a[i] — вес i-го жителя.n > 1) и нет ни одной пары людей, которая могла бы сесть вместе:
то лодка фактически одноместная.n > 1 с одноместной лодкой перевезти всех нельзя (кто-то должен возвращать лодку обратно, и мы зацикливаемся).-1.Назовём человека одиночкой, если он ни с кем не может плыть в одной лодке:
Таких людей посчитаем: L.
Остальные люди могут хотя бы с кем-то плыть вместе.
Оказывается (и это можно строго доказать), что:
Если задача вообще выполнима, то минимальное число переправ равно
где
L— количество одиночек.
L = 0) получаем классическую задачу:
переправ достаточно, чтобы перевезти всех.n = 1) заставляет добавить ещё 2 переправы.Для n = 1:
L = 1),2*1 - 3 + 2*1 = 1 — действительно нужна одна поездка.Алгоритм:
n, w и массив весов a.a[i] > w, сразу вывести -1.(i, j):
a[i] + a[j] <= w, отметить, что:
i и j не одиночки.n > 1 и ни одной пары не нашлось — вывести -1.L.cppans = 2 * n - 3 + 2 * L;
Сложность — O(n^2) на перебор пар, при n ≤ 1000 это нормально.
cpp#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; long long w; if (!(cin >> n >> w)) return 0; vector<long long> a(n); for (int i = 0; i < n; ++i) { cin >> a[i]; } // 1. Проверка: кто-то тяжелее лодки for (int i = 0; i < n; ++i) { if (a[i] > w) { cout << -1 << '\n'; return 0; } } // 2. Находим пары и помечаем тех, кто может с кем-то плыть vector<bool> canPair(n, false); bool hasPair = false; for (int i = 0; i < n; ++i) { for (int j = i + 1; j < n; ++j) { if (a[i] + a[j] <= w) { hasPair = true; canPair[i] = canPair[j] = true; } } } // Если людей > 1 и нет ни одной пары - задача невозможна if (n > 1 && !hasPair) { cout << -1 << '\n'; return 0; } // 3. Считаем одиночек int L = 0; for (int i = 0; i < n; ++i) { if (!canPair[i]) ++L; } // 4. Считаем ответ по формуле long long ans = 2LL * n - 3 + 2LL * L; cout << ans << '\n'; return 0; }
Если хочешь, могу ещё нарисовать конкретный оптимальный план поездок для какого-нибудь теста, чтобы стало интуитивно понятно, откуда берётся формула.