結果
問題 | No.2675 KUMA |
ユーザー | hitonanode |
提出日時 | 2024-03-15 22:48:19 |
言語 | Python3 (3.12.2 + numpy 1.26.4 + scipy 1.12.0) |
結果 |
AC
|
実行時間 | 1,741 ms / 2,000 ms |
コード長 | 10,652 bytes |
コンパイル時間 | 246 ms |
コンパイル使用メモリ | 13,824 KB |
実行使用メモリ | 133,396 KB |
最終ジャッジ日時 | 2024-09-30 02:19:15 |
合計ジャッジ時間 | 70,414 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge1 |
外部呼び出し有り |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1,741 ms
69,948 KB |
testcase_01 | AC | 1,366 ms
68,268 KB |
testcase_02 | AC | 1,145 ms
69,556 KB |
testcase_03 | AC | 1,167 ms
69,932 KB |
testcase_04 | AC | 1,255 ms
69,436 KB |
testcase_05 | AC | 1,392 ms
70,200 KB |
testcase_06 | AC | 1,366 ms
70,064 KB |
testcase_07 | AC | 1,362 ms
69,556 KB |
testcase_08 | AC | 1,388 ms
69,932 KB |
testcase_09 | AC | 1,162 ms
69,420 KB |
testcase_10 | AC | 1,165 ms
69,816 KB |
testcase_11 | AC | 1,248 ms
69,804 KB |
testcase_12 | AC | 1,256 ms
69,968 KB |
testcase_13 | AC | 1,344 ms
69,428 KB |
testcase_14 | AC | 1,368 ms
69,816 KB |
testcase_15 | AC | 1,385 ms
69,560 KB |
testcase_16 | AC | 1,418 ms
69,844 KB |
testcase_17 | AC | 1,362 ms
69,564 KB |
testcase_18 | AC | 1,359 ms
69,684 KB |
testcase_19 | AC | 1,403 ms
70,076 KB |
testcase_20 | AC | 1,377 ms
69,532 KB |
testcase_21 | AC | 1,375 ms
70,072 KB |
testcase_22 | AC | 1,368 ms
69,816 KB |
testcase_23 | AC | 1,392 ms
69,944 KB |
testcase_24 | AC | 1,362 ms
69,820 KB |
testcase_25 | AC | 1,200 ms
70,324 KB |
testcase_26 | AC | 1,393 ms
69,428 KB |
testcase_27 | AC | 1,368 ms
69,936 KB |
testcase_28 | AC | 1,366 ms
69,804 KB |
testcase_29 | AC | 1,377 ms
69,556 KB |
testcase_30 | AC | 1,380 ms
70,056 KB |
testcase_31 | AC | 1,376 ms
70,104 KB |
testcase_32 | AC | 1,383 ms
69,816 KB |
testcase_33 | AC | 1,368 ms
69,696 KB |
testcase_34 | AC | 1,294 ms
69,556 KB |
testcase_35 | AC | 1,284 ms
69,812 KB |
testcase_36 | AC | 1,206 ms
69,816 KB |
testcase_37 | AC | 1,172 ms
69,688 KB |
testcase_38 | AC | 1,213 ms
69,796 KB |
testcase_39 | AC | 1,378 ms
70,068 KB |
testcase_40 | AC | 1,392 ms
70,072 KB |
testcase_41 | AC | 1,437 ms
69,808 KB |
testcase_42 | AC | 1,453 ms
69,936 KB |
testcase_43 | AC | 1,361 ms
69,804 KB |
testcase_44 | AC | 1,183 ms
69,808 KB |
testcase_45 | AC | 1,308 ms
69,816 KB |
testcase_46 | AC | 1,426 ms
69,948 KB |
testcase_47 | AC | 1,391 ms
69,464 KB |
testcase_48 | AC | 1,402 ms
133,396 KB |
ソースコード
from enum import Enum from typing import SupportsFloat from scipy.optimize import linprog # type: ignore class LPVarType(Enum): CONTINUOUS = 1 INTEGER = 2 class _LPBase: def __add__(self, other: "LPExpressionLike") -> "LPExpression": return LPExpression.build(self) + other def __radd__(self, other: "LPExpressionLike") -> "LPExpression": return other + LPExpression.build(self) def __sub__(self, other: "LPExpressionLike") -> "LPExpression": return LPExpression.build(self) - other def __rsub__(self, other: "LPExpressionLike") -> "LPExpression": return other - LPExpression.build(self) def __mul__(self, other: SupportsFloat) -> "LPExpression": return LPExpression.build(self) * other def __rmul__(self, other: SupportsFloat) -> "LPExpression": return LPExpression.build(self) * other def __truediv__(self, other: SupportsFloat) -> "LPExpression": return LPExpression.build(self) / other def __neg__(self) -> "LPExpression": return -LPExpression.build(self) def __le__( self, other: "LPExpressionLike", ) -> "LPInequality": return LPInequality( lhs=LPExpression.build(self), rhs=other, inequality_type=LPInequalityType.LESSEQ, ) def __ge__( self, other: "LPExpressionLike", ) -> "LPInequality": return LPInequality( lhs=other, rhs=LPExpression.build(self), inequality_type=LPInequalityType.LESSEQ, ) def __eq__( # type: ignore self, other: "LPExpressionLike", ) -> "LPInequality": return LPInequality( lhs=LPExpression.build(self), rhs=other, inequality_type=LPInequalityType.EQUAL, ) class LPVar(_LPBase): def __init__( self, name: str, lower_bound: float | None = None, upper_bound: float | None = None, variable_type: LPVarType = LPVarType.CONTINUOUS, ) -> None: self.name = name self.lower_bound: float | None = lower_bound self.upper_bound: float | None = upper_bound self.variable_type: LPVarType = variable_type self._value: float | None = None def __str__(self) -> str: s = "{}(lb={}, ub={}, type={})".format( self.name, self.lower_bound, self.upper_bound, self.variable_type.name, ) if self._value is not None: s += ": {}".format(self._value) return s def __repr__(self) -> str: return str(self) def value(self) -> float | None: return self._value class LPInequalityType(Enum): LESSEQ = 1 # lhs <= rhs EQUAL = 2 # lhs == rhs class _LPTerm(_LPBase): """ A term of the form coefficient * variable. """ def __init__(self, coefficient: float, variable: LPVar) -> None: self.coefficient: float = coefficient self.variable: LPVar = variable class LPExpression: def __init__( self, const: SupportsFloat, terms: list[_LPTerm], ) -> None: self.const = float(const) self.terms = terms.copy() self._value: float | None = None @classmethod def build(self, x: "LPExpressionLike | _LPBase") -> "LPExpression": if isinstance(x, LPExpression): return LPExpression(x.const, x.terms) elif isinstance(x, _LPTerm): return LPExpression(0, [x]) elif isinstance(x, LPVar): return LPExpression(0, [_LPTerm(1.0, x)]) elif isinstance(x, SupportsFloat): return LPExpression(x, []) else: raise TypeError("Invalid type for LPExpression") def __add__(self, other: "LPExpressionLike") -> "LPExpression": rhs = LPExpression.build(other) return LPExpression( self.const + rhs.const, self.terms + rhs.terms, ) def __radd__(self, other: "LPExpressionLike") -> "LPExpression": return self + other def __sub__(self, other: "LPExpressionLike") -> "LPExpression": rhs = LPExpression.build(other) return self + (-rhs) def __rsub__(self, other: "LPExpressionLike") -> "LPExpression": return LPExpression.build(other) + (-self) def __mul__(self, other: SupportsFloat) -> "LPExpression": return LPExpression( self.const * float(other), [ _LPTerm( t.coefficient * float(other), t.variable, ) for t in self.terms ], ) def __rmul__(self, other: SupportsFloat) -> "LPExpression": return self * other def __truediv__(self, other: SupportsFloat) -> "LPExpression": return LPExpression( self.const / float(other), [ _LPTerm( t.coefficient / float(other), t.variable, ) for t in self.terms ], ) def __neg__(self) -> "LPExpression": return LPExpression( -self.const, [_LPTerm(-t.coefficient, t.variable) for t in self.terms], ) def __le__( self, other: "LPExpressionLike", ) -> "LPInequality": return LPInequality(self, other, LPInequalityType.LESSEQ) def __ge__( self, other: "LPExpressionLike", ) -> "LPInequality": return LPInequality(other, self, LPInequalityType.LESSEQ) def __eq__( # type: ignore self, other: "LPExpressionLike", ) -> "LPInequality": return LPInequality(self, other, LPInequalityType.EQUAL) def __str__(self) -> str: ret = ["{}".format(self.const)] for t in self.terms: sgn = "+" if t.coefficient >= 0 else "" ret.append("{}{}{}".format(sgn, t.coefficient, t.variable.name)) return " ".join(ret) def value(self) -> float | None: return self._value LPExpressionLike = LPExpression | _LPTerm | LPVar | SupportsFloat class LPInequality: def __init__( self, lhs: LPExpressionLike, rhs: LPExpressionLike, inequality_type: LPInequalityType, ) -> None: """ lhs <= rhs -> terms + const (<= or ==) 0 """ self.lhs = LPExpression.build(lhs) - LPExpression.build(rhs) self.inequality_type = inequality_type def __str__(self) -> str: if self.inequality_type == LPInequalityType.LESSEQ: return "{} <= 0".format(self.lhs) elif self.inequality_type == LPInequalityType.EQUAL: return "{} == 0".format(self.lhs) else: raise ValueError("Invalid inequality type") def __repr__(self) -> str: return str(self) class LPModel: def __init__(self) -> None: self.constraints: list[LPInequality] = [] self.objective: LPExpression = LPExpression(0, []) def add_constraint(self, constraint: LPInequality) -> None: self.constraints.append(constraint) def set_objective(self, objective: LPExpressionLike) -> None: self.objective = LPExpression.build(objective) def solve(self) -> bool: var_dict: dict[int, LPVar] = {} for constraint in self.constraints: for term in constraint.lhs.terms: var_dict.setdefault(id(term.variable), term.variable) for term in self.objective.terms: var_dict.setdefault(id(term.variable), term.variable) id_to_idx = {id(v): i for i, v in enumerate(var_dict.values())} A_ub: list[list[float]] = [] b_ub: list[float] = [] A_eq: list[list[float]] = [] b_eq: list[float] = [] for constraint in self.constraints: lhs: list[float] = [0.0] * len(var_dict) rhs = -constraint.lhs.const for term in constraint.lhs.terms: lhs[id_to_idx[id(term.variable)]] += term.coefficient if constraint.inequality_type == LPInequalityType.LESSEQ: A_ub.append(lhs) b_ub.append(rhs) elif constraint.inequality_type == LPInequalityType.EQUAL: A_eq.append(lhs) b_eq.append(rhs) else: raise ValueError("Invalid inequality type") bounds = [(v.lower_bound, v.upper_bound) for v in var_dict.values()] integrality = [ int(variable.variable_type == LPVarType.INTEGER) for variable in var_dict.values() ] c: list[float] = [0.0] * len(var_dict) for term in self.objective.terms: c[id_to_idx[id(term.variable)]] += term.coefficient res = linprog( c, A_ub=A_ub or None, b_ub=b_ub or None, A_eq=A_eq or None, b_eq=b_eq or None, bounds=bounds, integrality=integrality, ) if res.status == 0: for i, variable in enumerate(var_dict.values()): variable._value = res.x[i] self.objective._value = res.fun + self.objective.const return True else: return False N = int(input()) xys = [tuple(map(int, input().split())) for _ in range(N)] keimas = [ (2, -1), (2, 1), (-2, -1), (-2, 1), (1, 2), (1, -2), (-1, 2), (-1, -2), ] targets = [] for x, y in xys: targets.extend([(x + a, y + b) for a, b in keimas]) targets = sorted(set(targets) - set(xys)) lp = LPModel() dirs = [ [(2, -1), (2, 1)], [(-2, -1), (-2, 1)], [(-1, -2), (1, -2)], [(-1, 2), (1, 2)], ] sgns = { (i, d): LPVar( f"x{i}_{d}", lower_bound=0, upper_bound=1, variable_type=LPVarType.INTEGER ) for i in range(len(targets)) for d in range(len(dirs)) } for j in range(N): vs = [] for i, (x, y) in enumerate(targets): for d, dir in enumerate(dirs): match = False for dx, dy in dir: if (x + dx, y + dy) == xys[j]: match = True break if match: vs.append(sgns[i, d]) if vs: lp.add_constraint(sum(vs) >= 1) else: print(-1) exit() for i in range(len(targets)): lp.add_constraint(sum([sgns[i, d] for d in range(len(dirs))]) <= 1) lp.set_objective(sum(sgns.values())) if lp.solve(): print(int(lp.objective.value() + 0.1)) else: print(-1)