Submission #23995467


Source Code Expand

import sys
from typing import NamedTuple, Optional, List, cast

input = sys.stdin.readline


# ref:
# https://github.com/not522/ac-library-python/blob/master/atcoder/maxflow.py
class MFGraph:
    class Edge(NamedTuple):
        src: int
        dst: int
        cap: int
        flow: int

    class _Edge:
        def __init__(self, dst: int, cap: int) -> None:
            self.dst = dst
            self.cap = cap
            self.rev: Optional[MFGraph._Edge] = None

    def __init__(self, n: int) -> None:
        self._n = n
        self._g: List[List[MFGraph._Edge]] = [[] for _ in range(n)]
        self._edges: List[MFGraph._Edge] = []

    def add_edge(self, src: int, dst: int, cap: int) -> int:
        assert 0 <= src < self._n
        assert 0 <= dst < self._n
        assert 0 <= cap
        m = len(self._edges)
        e = MFGraph._Edge(dst, cap)
        re = MFGraph._Edge(src, 0)
        e.rev = re
        re.rev = e
        self._g[src].append(e)
        self._g[dst].append(re)
        self._edges.append(e)
        return m

    def get_edge(self, i: int) -> Edge:
        assert 0 <= i < len(self._edges)
        e = self._edges[i]
        re = cast(MFGraph._Edge, e.rev)
        return MFGraph.Edge(
            re.dst,
            e.dst,
            e.cap + re.cap,
            re.cap
        )

    def edges(self) -> List[Edge]:
        return [self.get_edge(i) for i in range(len(self._edges))]

    def change_edge(self, i: int, new_cap: int, new_flow: int) -> None:
        assert 0 <= i < len(self._edges)
        assert 0 <= new_flow <= new_cap
        e = self._edges[i]
        e.cap = new_cap - new_flow
        assert e.rev is not None
        e.rev.cap = new_flow

    def flow(self, s: int, t: int, flow_limit: Optional[int] = None) -> int:
        assert 0 <= s < self._n
        assert 0 <= t < self._n
        assert s != t
        if flow_limit is None:
            flow_limit = cast(int, sum(e.cap for e in self._g[s]))

        current_edge = [0] * self._n
        level = [0] * self._n

        def fill(arr: List[int], value: int) -> None:
            for i in range(len(arr)):
                arr[i] = value

        def bfs() -> bool:
            fill(level, self._n)
            queue = []
            q_front = 0
            queue.append(s)
            level[s] = 0
            while q_front < len(queue):
                v = queue[q_front]
                q_front += 1
                next_level = level[v] + 1
                for e in self._g[v]:
                    if e.cap == 0 or level[e.dst] <= next_level:
                        continue
                    level[e.dst] = next_level
                    if e.dst == t:
                        return True
                    queue.append(e.dst)
            return False

        def dfs(lim: int) -> int:
            stack = []
            edge_stack: List[MFGraph._Edge] = []
            stack.append(t)
            while stack:
                v = stack[-1]
                if v == s:
                    flow = min(lim, min(e.cap for e in edge_stack))
                    for e in edge_stack:
                        e.cap -= flow
                        assert e.rev is not None
                        e.rev.cap += flow
                    return flow
                next_level = level[v] - 1
                while current_edge[v] < len(self._g[v]):
                    e = self._g[v][current_edge[v]]
                    re = cast(MFGraph._Edge, e.rev)
                    if level[e.dst] != next_level or re.cap == 0:
                        current_edge[v] += 1
                        continue
                    stack.append(e.dst)
                    edge_stack.append(re)
                    break
                else:
                    stack.pop()
                    if edge_stack:
                        edge_stack.pop()
                    level[v] = self._n
            return 0

        flow = 0
        while flow < flow_limit:
            if not bfs():
                break
            fill(current_edge, 0)
            while flow < flow_limit:
                f = dfs(flow_limit - flow)
                flow += f
                if f == 0:
                    break
        return flow

    def min_cut(self, s: int) -> List[bool]:
        visited = [False] * self._n
        stack = [s]
        visited[s] = True
        while stack:
            v = stack.pop()
            for e in self._g[v]:
                if e.cap > 0 and not visited[e.dst]:
                    visited[e.dst] = True
                    stack.append(e.dst)
        return visited


def main():
    n, w = map(int, input().split())
    a = list(map(int, input().split()))
    S = n
    T = n + 1
    mf = MFGraph(n + 2)
    inf = 1 << 30
    for i in range(n):
        mf.add_edge(S, i, w)
        mf.add_edge(i, T, a[i])

    for i in range(n):
        v = [int(j) - 1 for j in input().split()[1:]]
        for j in v:
            mf.add_edge(i, j, inf)

    print(sum(a) - mf.flow(S, T))


if __name__ == "__main__":
    main()

Submission Info

Submission Time
Task 040 - Get More Money(★7)
User riantkb
Language Python (3.8.2)
Score 7
Code Size 5041 Byte
Status AC
Exec Time 49 ms
Memory 11704 KiB

Judge Result

Set Name Sample All
Score / Max Score 0 / 0 7 / 7
Status
AC × 2
AC × 12
Set Name Test Cases
Sample sample01.txt, sample02.txt
All free.txt, killer.txt, max_densest01.txt, max_densest02.txt, max_random00.txt, max_random01.txt, max_random02.txt, random00.txt, random01.txt, random02.txt, sample01.txt, sample02.txt
Case Name Status Exec Time Memory
free.txt AC 35 ms 10064 KiB
killer.txt AC 46 ms 10360 KiB
max_densest01.txt AC 45 ms 11704 KiB
max_densest02.txt AC 49 ms 11696 KiB
max_random00.txt AC 35 ms 10540 KiB
max_random01.txt AC 44 ms 10780 KiB
max_random02.txt AC 33 ms 10236 KiB
random00.txt AC 38 ms 10444 KiB
random01.txt AC 37 ms 10540 KiB
random02.txt AC 32 ms 10336 KiB
sample01.txt AC 38 ms 10308 KiB
sample02.txt AC 33 ms 10024 KiB