結果

問題 No.957 植林
ユーザー 👑 KazunKazun
提出日時 2021-08-26 02:11:14
言語 PyPy3
(7.3.15)
結果
TLE  
実行時間 -
コード長 8,928 bytes
コンパイル時間 227 ms
コンパイル使用メモリ 82,304 KB
実行使用メモリ 223,860 KB
最終ジャッジ日時 2024-04-28 17:19:23
合計ジャッジ時間 16,388 ms
ジャッジサーバーID
(参考情報)
judge5 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 47 ms
60,800 KB
testcase_01 AC 45 ms
55,296 KB
testcase_02 AC 47 ms
55,168 KB
testcase_03 AC 1,270 ms
190,956 KB
testcase_04 AC 1,346 ms
185,216 KB
testcase_05 AC 1,097 ms
194,952 KB
testcase_06 AC 1,701 ms
204,508 KB
testcase_07 AC 1,488 ms
188,824 KB
testcase_08 AC 548 ms
183,384 KB
testcase_09 AC 536 ms
182,860 KB
testcase_10 AC 571 ms
188,920 KB
testcase_11 AC 561 ms
184,364 KB
testcase_12 AC 552 ms
182,276 KB
testcase_13 AC 455 ms
169,884 KB
testcase_14 AC 500 ms
191,288 KB
testcase_15 AC 478 ms
178,952 KB
testcase_16 AC 454 ms
170,324 KB
testcase_17 AC 450 ms
170,580 KB
testcase_18 TLE -
testcase_19 -- -
testcase_20 -- -
testcase_21 -- -
testcase_22 -- -
testcase_23 -- -
testcase_24 -- -
testcase_25 -- -
testcase_26 -- -
testcase_27 -- -
testcase_28 -- -
testcase_29 -- -
testcase_30 -- -
testcase_31 -- -
testcase_32 -- -
testcase_33 -- -
testcase_34 -- -
testcase_35 -- -
testcase_36 -- -
testcase_37 -- -
testcase_38 -- -
testcase_39 -- -
testcase_40 -- -
testcase_41 -- -
testcase_42 -- -
testcase_43 -- -
testcase_44 -- -
testcase_45 -- -
testcase_46 -- -
testcase_47 -- -
権限があれば一括ダウンロードができます

ソースコード

diff #

#Thansk for  aaaaaaaaaa2230
#URL:https://atcoder.jp/contests/practice2/submissions/17017319
import sys
from collections import deque
class MaxFlow:
    class Edge:
        def __init__(self,target,cap,base,direct):
            self.target = target
            self.cap = cap
            self.flow=0
            self.base=base
            self.direct=direct
            self.rev = None

        def __str__(self):
            if self.direct==1:
                return "[S](target:{}, flow/cap:{}/{})".format(self.target,self.flow,self.base)
            else:
                return "[T](source:{}, flow/cap:{}/{})".format(self.target,self.flow,self.base)

        __repr__=__str__

    def __init__(self,N):
        """ N 頂点からなる Flow 場を生成する.
        """

        self.N = N
        self.graph = [[] for _ in range(N)]
        self.old_flow=0

    def add_edge(self,u,v, cap):
        """ 容量が cap である有向辺 u→v を加える.

        u,v: 頂点
        cap: 容量
        """
        graph = self.graph
        edge = self.Edge(v,cap,cap,1)
        edge2 = self.Edge(u,0,cap,-1)
        edge.rev = edge2
        edge2.rev = edge
        graph[u].append(edge)
        graph[v].append(edge2)

    def __bfs(self, s, t):
        level = self.level = [self.N]*self.N
        q = deque([s])
        level[s] = 0
        while q:
            now = q.popleft()
            lw = level[now]+1
            for e in self.graph[now]:
                if e.cap and level[e.target]> lw:
                    level[e.target] = lw
                    if e.target == t:
                        return True
                    q.append(e.target)
        return False

    def __dfs(self, s, t, up):
        graph = self.graph
        it = self.it
        level = self.level

        st = deque([t])
        while st:
            v = st[-1]
            if v == s:
                st.pop()
                flow = up
                for w in st:
                    e = graph[w][it[w]].rev
                    flow = min(flow, e.cap)
                for w in st:
                    e = graph[w][it[w]]
                    e.cap += flow
                    e.flow-=flow
                    e.rev.cap -= flow
                    e.rev.flow+=flow
                return flow
            lv = level[v]-1
            while it[v] < len(graph[v]):
                e = graph[v][it[v]]
                re = e.rev
                if re.cap == 0 or lv != level[e.target]:
                    it[v] += 1
                    continue
                st.append(e.target)
                break
            if it[v] == len(graph[v]):
                st.pop()
                level[v] = self.N

        return 0

    def max_flow(self,source,target,flow_limit=float("inf")):
        """ source から target に流す最大流の大きさを出力する.

        source, target: 頂点
        flow_limit: "追加で流す" 最大流の上限
        """

        Flow=0
        while Flow < flow_limit and self.__bfs(source,target):
            self.it=[0]*self.N
            while Flow<flow_limit:
                F=self.__dfs(source,target,flow_limit-Flow)
                if F==0:break
                Flow+=F
        self.old_flow+=Flow
        return self.old_flow

    def flow(self):
        """ 現在の flow の状況を求める.

        [Output]
        辞書 D が返る. D[u][v] で 有効辺 u→v に流れる量を表す.
        """

        X=[{} for _ in range(self.N)]
        for i in range(self.N):
            x=X[i]
            for e in self.graph[i]:
                if e.direct==-1: continue
                if e.target not in x: x[e.target]=0
                x[e.target]+=e.flow
        return X

    def min_cut(self,s):
        """ sにおける最小カットを求める.

        [Input]
        s: sorce (s が 0 側になる)

        [Output]
        0 or 1 のリストで, 0同士と1同士で分ける.
        """
        visited = [1]*self.N
        q = deque([s]); visited[s]=0
        while q:
            v = q.pop()
            for e in self.graph[v]:
                if e.cap and visited[e.target]==1:
                    visited[e.target]=0
                    q.append(e.target)
        return visited

inf=float("inf")
class Project_Selection_Problem:
    def __init__(self,N):
        """ N 要素の Project Selection Problem を生成する.

        N:int
        """

        self.N=N
        self.ver_num=N+2
        self.source=N
        self.base=0
        self.target=N+1
        self.indivi=[[0,0] for _ in range(N+2)]
        self.mutual=[]

    def set_zero_one(self,x,y,a):
        """ h(x)=0,  h(y)=1 のとき, a (<=0) 点を得るという条件を追加する.

        0<=x,y<N
        a<=0
        """

        assert 0<=x<self.N
        assert 0<=y<self.N
        assert a<=0

        self.mutual.append((x,y,-a))

    def set_zero(self,x,a):
        """ h(x)=0 のとき, a 点を得るという条件を追加する.

        0<=x<N
        """

        assert 0<=x<self.N
        self.indivi[x][0]+=a

    def set_one(self,x,a):
        """ h(x)=1 のとき, a 点を得るという条件を追加する.

        0<=x<N
        """

        assert 0<=x<self.N
        self.indivi[x][1]+=a

    def set_all_zero(self,X,a):
        """ h(x)=0 (forall x in X) のとき, a (>=0) 点を得るという条件を追加する.

        0<=x<N
        a>=0
        """

        assert a>=0

        self.indivi.append([None,None])
        self.ver_num+=1
        self.base+=a

        self.indivi[-1][0]=-a
        for x in X:
            assert 0<=x<self.N
            self.mutual.append((self.ver_num-1,x,inf))


    def set_all_one(self,X,a):
        """ h(x)=1 (forall x in X) のとき, a (>=0) 点を得るという条件を追加する.

        0<=x<N
        a>=0
        """

        assert a>=0

        self.indivi.append([None,None])
        self.ver_num+=1
        self.base+=a

        self.indivi[-1][1]=-a
        for x in X:
            assert 0<=x<self.N
            self.mutual.append((x,self.ver_num-1,inf))

    def set_not_equal(self,x,y,a):
        """ h(x)!=h(y) ならば, a (<=0) 点を得るという条件を追加する.

        0<=x,y<N
        a<=0
        """

        assert 0<=x<self.N and 0<=y<self.N
        assert a<=0

        self.set_zero_one(x,y,a)
        self.set_zero_one(y,x,a)

    def set_equal(self,x,y,a):
        """ h(x)=h(y) ならば, a (>=0) 点を得るという条件を追加する.

        0<=x,y<N
        a>=0
        """

        assert 0<=x<self.N and 0<=y<self.N
        assert a>=0

        self.set_all_zero([x,y],a)
        self.set_all_one([x,y],a)

    def ban_zero(self,x):
        """ h(x)=0 となることを禁止する. (実行したら -inf 点になる)

        0<=x<N
        """

        assert 0<=x<self.N
        self.set_zero(x,-inf)

    def ban_one(self,x):
        """ h(x)=1 となることを禁止する. (実行したら -inf 点になる)

        0<=x<N
        """

        assert 0<=x<self.N
        self.set_one(x,-inf)

    def solve(self,Mode=0):
        """ Project Selection Problem を解く.

        Mode
        0: 最大値のみ
        1: 最大値とそれを達成する例
        """

        F=MaxFlow(self.ver_num)
        base=self.base
        for i in range(self.N):
            F.add_edge(self.source,i,0)
            F.add_edge(i,self.target,0)

            if self.indivi[i][0]>=0:
                base+=self.indivi[i][0]
                F.add_edge(self.source,i,self.indivi[i][0])
            else:
                F.add_edge(i,self.target,-self.indivi[i][0])

            if self.indivi[i][1]>=0:
                base+=self.indivi[i][1]
                F.add_edge(i,self.target,self.indivi[i][1])
            else:
                F.add_edge(self.source,i,-self.indivi[i][1])

        for i in range(self.target+1,self.ver_num):
            if self.indivi[i][0]!=None:
                F.add_edge(self.source,i,-self.indivi[i][0])
            if self.indivi[i][1]!=None:
                F.add_edge(i,self.target,-self.indivi[i][1])

        for x,y,c in self.mutual:
            F.add_edge(x,y,c)

        alpha=F.max_flow(self.source,self.target)
        if Mode==0:
            return base-alpha
        else:
            return base-alpha,F.min_cut(self.source)[:self.N]
#==================================================
H,W=map(int,input().split())

G=[]
R_sum=[0]*H; C_sum=[0]*W

for i in range(H):
    g=list(map(int,input().split()))
    G.append(g)

    for j in range(W):
        R_sum[i]+=g[j]
        C_sum[j]+=g[j]


R=list(map(int,input().split()))
C=list(map(int,input().split()))

P=Project_Selection_Problem(H+W)

for i in range(H):
    P.set_one(i,R[i]-R_sum[i])

for j in range(W):
    P.set_one(j+H,C[j]-C_sum[j])

for i in range(H):
    for j in range(W):
        P.set_all_one([i,j+H],G[i][j])

print(P.solve(0))
0