Problem:


  MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

Matrix-chain Multiplication

  The goal of the matrix-chain multiplication problem is to find the most efficient way to multiply given $n$ matrices $M_1, M_2, M_3,...,M_n$.

  Write a program which reads dimensions of $M_i$, and finds the minimum number of scalar multiplications to compute the maxrix-chain multiplication $M_1M_2...M_n$.

Input

  In the first line, an integer $n$ is given. In the following $n$ lines, the dimension of matrix $M_i$ ($i = 1...n$) is given by two integers $r$ and $c$ which respectively represents the number of rows and columns of $M_i$.

Output

  Print the minimum number of scalar multiplication in a line.

Constraints

$1 \leq n \leq 100$

$1 \leq r, c \leq 100$

Sample Input 1

6
30 35
35 15
15 5
5 10
10 20
20 25

Sample Output 1

15125



Sample input:
6
30 35
35 15
15 5
5 10
10 20
20 25


Sample output:
15125

Submission status: Accepted

Solution code:
N = int(input())
R = [0]*N
C = [0]*N
for i in range(N):
    R[i],C[i] = map(int, input().split())
    
DP = [[0 for _ in range(N)] for _ in range(N)]

for i in range(N):
    DP[i][i] = 0

for l in range(1, N):
    for r in range(N-l):
        ri = R[r]
        le = C[r+l]
        DP[r][r+l] = min(ri*C[k]*le+DP[r][k]+DP[k+1][r+l] for k in range(r, r+l))
print(DP[0][N-1])

Submission status: Accepted

Solution code:
import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]
def dp3(ini, i, j, k): return [[[ini]*i for _ in range(j)] for _ in range(k)]
#import bisect #bisect.bisect_left(B, a)
#from collections import defaultdict #d = defaultdict(int) d[key] += value
#from itertools import accumulate #list(accumulate(A))

N = ii()
l = li2(N)


'''
# メモ化再帰
dp = dp2(-1, N, N)
def rec(i, j):
    if dp[i][j] != -1:
        return dp[i][j]
    if i == j:
        dp[i][j] = 0
        return 0
    if j-i == 1:
        dp[i][j] = l[i][0] * l[i][1] * l[j][1]
        return dp[i][j]
    res = float('inf')
    for k in range(i, j):
        res = min(res, rec(i, k) + rec(k+1, j) + l[i][0] * l[k+1][0] * l[j][1])
    dp[i][j] = res
    return res

print(rec(0, N-1))
'''

# 2次元DP

dp = dp2(float('inf'), N, N)

for i in range(N):
    dp[i][i] = 0

for h in range(1, N):
    for i in range(N):
        if i+h < N:
            if h == 1:
                dp[i][i+h] = l[i][0] * l[i][1] * l[i+h][1]
            else:
                #dp[i][i+h] = dp[i][i+h-1] + l[i][0] * l[i+h][0] * l[i+h][1]
                for r in range(i, i+h):
                    dp[i][i+h] = min(dp[i][i+h], dp[i][r]+dp[r+1][i+h]+l[i][0]*l[r+1][0]*l[i+h][1])
#print(dp)
print(dp[0][N-1])

Submission status: Accepted

Solution code:
inf = 10**9+7
mod = 10**9+7
n = int(input())
rc = [list(map(int, input().split())) for i in range(n)]
dp = [[inf for j in range(n)]for i in range(n)]
for i in range(n):
    dp[i][i] = 0
for k in range(1,n):
    for i in range(0,n-k):
        for j in range(k):
            dp[i][i+k] = min(dp[i][i+k], dp[i][i+j] + dp[i+j+1][i+k] + rc[i][0]*rc[i+j][1]*rc[i+k][1])
print(dp[0][n-1])

Submission status: Accepted

Solution code:
#!/usr/bin/env python3

from pprint import pprint
import sys

sys.setrecursionlimit(10 ** 6)
input = sys.stdin.buffer.readline

n = int(input())
l_dim = []
for _ in range(n):
    row, col = map(int, input().split())
    l_dim.append([row, col])
# print(l_dim)

# dp[i][j]: M_i M_{i+1} ... M_jのスカラー乗算回数の最小値
# M_i M_jのスカラー乗算回数 = row_i * col_j * col_i
# 行列 M_i ... M_k と行列 M_{k+1} ... M_j の積を考え、最小値を更新していく
# dp[i][j]: min(dp[i][j], dp[M_i][M_k] + dp[M_{k+1}][M_j] + row_i * col_j * col_k)
# ただし、i <= k <= j

dp = [[-1 for j in range(n)] for i in range(n)]


def rec_dp(left, right):
    if dp[left][right] >= 0:
        # 既に最小値が決まっている
        return dp[left][right]
    if left == right:
        # dp[i][i] = 0
        return 0

    row_left = l_dim[left][0]
    col_right = l_dim[right][1]
    res = float("inf")
    for k in range(left, right):
        col_k = l_dim[k][1]
        num = row_left * col_right * col_k
        res = min(res, rec_dp(left, k) + rec_dp(k + 1, right) + num)
    dp[left][right] = res

    return dp[left][right]


print(rec_dp(0, n - 1))

Submission status: Accepted

Solution code:
n = int(input())

N = 101

p = [0] * N
m = [[0] * N for _ in range(N)]

for i in range(1, n + 1):
	p[i - 1], p[i] = map(int, input().split())

# print(p)

for l in range(2, n + 1):
	for i in range(1, n - l + 2):
		j = i + l - 1
		m[i][j] = float('inf')
		for k in range(i, j):
			m[i][j] = min(m[i][j], m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j])

print(m[1][n])

Submission status: Accepted

Solution code:
import math
import copy
import sys
import fractions
# import numpy as np
# import statistics
import decimal
import heapq
import collections
import itertools
import bisect

# from operator import mul

sys.setrecursionlimit(100001)


# input = sys.stdin.readline
# sys.setrecursionlimit(10**6)

# ===FUNCTION===

def getInputIntList():
    outputDataList = []
    inputData = input().split()
    outputDataList = [int(n) for n in inputData]

    return outputDataList


def getSomeInputInt(n):
    outputDataList = []
    for i in range(n):
        inputData = int(input())
        outputDataList.append(inputData)

    return outputDataList


def getSomeInputListInt(n):
    inputDataList = []
    outputDataList = []
    for i in range(n):
        inputData = input().split()
        inputDataList = [int(n) for n in inputData]
        outputDataList.append(inputDataList)

    return outputDataList


# ===CODE===


n = int(input())

data_set = getSomeInputListInt(n)
data_set.insert(0, 0)

INF = sys.maxsize

dp = [[INF for _ in range(n+1)] for _ in range(n+1)]
for i in range(1, n+1):
    dp[i][i] = 0
next_dp = copy.deepcopy(dp)

# ans = INF
# for s in range(1, n):
#     for i in range(1, n+1):
#         for j in range(i+s, n+1):
#             for k in range(i, j+1):
#                 if k >
#                 if dp[i][k] < INF and dp[k+1][j] < INF:
#                     next_dp[i][j] = min(next_dp[i][j], dp[i][k]+dp[k+1][j]+data_set[i][0]*data_set[k][1]*data_set[j][0])
#
#     dp = next_dp
#     ans = min(ans, dp[1][n])
# print(ans)


for s in range(1, n):
    for i in range(1, n+1):
        j = i+s
        if j > n:
            break
        for k in range(i, j):
            if dp[i][k] < INF and dp[k+1][j] < INF:
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + data_set[i][0] * data_set[k][1] * data_set[j][1])

print(dp[1][n])

Submission status: Accepted

Solution code:
# -*- coding: utf-8 -*-
import sys
INF=10**9
MOD=10**9+7
input=lambda: sys.stdin.readline().rstrip()

def main():
    N=int(input())
    R,C=[0]*N,[0]*N
    A=[0]*(N+1)
    for i in range(N):
        A[i],A[i+1]=map(int,input().split())
    dp=[[INF]*N for _ in range(N)]
    dp[0]=[0]*N
    for i in range(N):
        for j in range(N-1-i):
            for k in range(i+1):
                dp[i+1][j]=min(dp[i+1][j],dp[i-k][j]+dp[k][i+1-k+j]+A[j]*A[j+i+1-k]*A[j+i+2])
    print(dp[-1][0])

if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
import sys
from functools import lru_cache
input = sys.stdin.readline
sys.setrecursionlimit(2 * 10**6)


def inpl():
    return list(map(int, input().split()))


def main():
    @lru_cache(maxsize=None)
    def recur(i, j):
        # print(i, j)
        if i == j:
            return 0
        for k in range(i, j):
            c = recur(i, k) + recur(k + 1, j) + P[i] * P[k + 1] * P[j + 1]
            if c < cost[i][j]:
                cost[i][j] = c
        return cost[i][j]

    N = int(input())
    RC = [inpl() for _ in range(N)]
    cost = [[float('inf')] * (N + 1) for a in range(N + 1)]
    P = [0] * (N + 1)
    for i, rc in enumerate(RC):
        P[i] = rc[0]
    P[N] = RC[N - 1][1]

    print(recur(0, N - 1))


if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
N = int(input())
R = [0]*(N)
C = [0]*(N)
for i in range(N):
    R[i], C[i] = map(int, input().split())

dp = [[1<<60]*(N+1) for i in range(N+1)]
for i in range(N+1):
    dp[i][i] = 0

for le in range(1, N):
    for i in range(N-le):
        j = i + le

        for k in range(i, j):
            tmp = dp[i][k] + dp[k+1][j] + R[i]*C[k]*C[j]
            dp[i][j] = min(dp[i][j], tmp)
print(dp[0][N-1])

Submission status: Accepted

Solution code:
mod = 10 ** 9 + 7
mod2 = 2 ** 61 + 1
from collections import deque
import heapq
import time
from bisect import bisect_left, insort_left, bisect_right
import sys
import random
import itertools

#input = sys.stdin.readline
def input():
    return sys.stdin.readline().strip("\n").strip(" ")

_NUMINT_ALL = list(range(10))
_START_TIME = time.time()
INDEX_KETA = 10**12

def main():
    ans = solve()

    if ans is True or ans is False:
        YesNo(ans)
    elif ans is None:
        return

    if isinstance(ans, tuple):
        split_print_space(ans)
    else:
        print(ans)


def solve():
    N = iip()
    M = iipt(N)
    R = [i[0] for i in M]
    R.append(M[-1][1])
    #print(R)

    dp = [[10**6 for _ in range(N)] for _ in range(N)]

    for i in range(N):
        dp[i][i] = 0


    for d in range(1, N+1): # 行列の個数
        for l in range(N+1):
            r = l + d
            if r+1 > N:
                continue

            kouho = []
            for k in range(l+1, r+1):
                #print(dp[k][r], R[l], R[r+1] ,R[k], l, k, r, R[l]*R[r+1]*R[k])
                kouho.append(dp[l][k-1] + dp[k][r] + R[l]*R[r+1]*R[k])

            dp[l][r] = min(kouho)

            #dp[l][r] = min(dp[l+1][r] + R[l]*R[l+1]*R[r+1], dp[l][r-1] +R[l]*R[r]*R[r+1])
            #fprint(dp)

    print(dp[0][-1])



#####################################################ライブラリ集ここから



def kiriage_warizan(a, b):
    return -(-a//b)

def iip(listed=False):  # 数字のinputをlistで受け取る
    d = input().rstrip("\n").split()
    try:
        ret = [int(i) for i in d]
    except:
        ret = [int(i) if i in _NUMINT_ALL else i for i in d]
        if len(ret) == 1 and listed is False:
            return ret[0]

    if len(ret) == 1 and not listed:
        return ret[0]
    return ret

def iipt(l, listed=True, num_only=True):  # 縦向きに並んでいるデータをリストに落とし込む(iip利用)
    if isinstance(l, list):
        l = l[0] # 間違って要素１個のタプルを渡されても受け取る
    ret = []
    for i in range(l):
        ret.append(iip(listed=listed))
    return ret


def saidai_kouyakusuu(A):  # 最大公約数
    l = len(A)
    while True:
        m = min(A)
        mx = max(A)
        if m == mx:
            return m

        for i in range(l):
            if A[i] % m == 0:
                A[i] = m
            else:
                A[i] %= m


def flatten(l):
    return list(itertools.chain.from_iterable(l))


def index_sorted(sorted_list, target):
    idx = bisect_left(sorted_list, target)
    if idx != len(sorted_list) and sorted_list[idx] == target:
        return idx
    else:
        return False


def time_debug_10percent():
    a = random.randint(0, 9)
    if a == 9:
        sys.exit()

def time_debug(t):
    time.sleep(_START_TIME + t - time.time())
    sys.exit()


def make_graph_edge_flat(N):  # グラフ作成のための辺をリストで返す
    ret = []
    for i in range(N-1):
        a, b, c = iip()
        a -= 1
        b -= 1
        ret[a].append((b, c))
        ret[b].append((a, c))
    return ret


def sort_tuples(l, index):  # タプルのリストを特定のインデックスでソートする
    if isinstance(l, list):
        l.sort(key=lambda x: x[index])
        return l
    else:
        l = list(l)
        return sorted(l, key=lambda x: x[index])


def count_elements(l):  # リストの中身の個数を種類分けして辞書で返す
    d = {}
    for i in l:
        if i in d:
            d[i] += 1
        else:
            d[i] = 1
    return d


def safeget(l, index, default="exception"):  # listの中身を取り出す時、listからはみ出たり
    if index >= len(l):                      # マイナスインデックスになったりするのを防ぐ
        if default == "exception":
            raise Exception("".join(["safegetに不正な値 ", index, "が渡されました。配列の長さは", len(l), "です"]))
        else:
            return default
    elif index < 0:
        if default == "exception":
            raise Exception("".join(["safegetに不正な値 ", index, "が渡されました。負の値は許可されていません"]))
        else:
            return default
    else:
        return l[index]


def sortstr(s):  # 文字列をソートする
    return "".join(sorted(s))


def iip_ord(startcode="a"):  # 文字列を数字の列に変換する(数字と文字は1:1対応)
    if isinstance(startcode, str):
        startcode = ord(startcode)
    return [ord(i) - startcode for i in input()]


def YesNo(s):  # TrueFalseや1, 0をYesNoに変換する
    if s:
        print("Yes")
    else:
        print("No")


def fprint(s):  # リストを平たくしてprintする(二次元リストを見やすくしたりとか)
    if isinstance(s, int):
        print(s)
    keta = max([len(str(i)) for i in itertools.chain.from_iterable(s)])
    for i in s:
        print([str(j).zfill(keta) for j in i])


def bitall(N):  # ビット全探索用のインデックスを出力
    ret = []
    for i in range(2 ** N):
        a = []
        for j in range(N):
            a.append(i % 2)
            i //= 2
        ret.append(a)
    return ret

def split_print_space(s):  # リストの中身をスペース区切りで出力する
    print(" ".join([str(i) for i in s]))


def split_print_enter(s):  # リストの中身を改行区切りで出力する
    print("\n".join([str(i) for i in s]))


def soinsuu_bunkai(n):  # 素因数分解
    ret = []
    for i in range(2, int(n ** 0.5) + 1):
        while n % i == 0:
            n //= i
            ret.append(i)
        if i > n:
            break
    if n != 1:
        ret.append(n)
    return ret


def conbination(n, r, mod, test=False):  # nCrをmodを使って計算する
    if n <= 0:
        return 0
    if r == 0:
        return 1
    if r < 0:
        return 0
    if r == 1:
        return n
    ret = 1
    for i in range(n - r + 1, n + 1):
        ret *= i
        ret = ret % mod

    bunbo = 1
    for i in range(1, r + 1):
        bunbo *= i
        bunbo = bunbo % mod

    ret = (ret * inv(bunbo, mod)) % mod
    if test:
        # print(f"{n}C{r} = {ret}")
        pass
    return ret


def inv(n, mod):  #  modnにおける逆元を計算
    return power(n, mod - 2)


def power(n, p, mod_=mod):  # 繰り返し二乗法でn**p % modを計算
    if p == 0:
        return 1
    if p % 2 == 0:
        return (power(n, p // 2, mod_) ** 2) % mod_
    if p % 2 == 1:
        return (n * power(n, p - 1, mod_)) % mod_


def nibutan_func(func, target, left, right, side="left", seido = 1): # 関数を二分探索
    l = left
    r = right
    if seido == 1:
        x = (l + r) // 2
    else:
        x = (l + r) / 2
    while r-l > seido:
        #print(x)
        if seido == 1:
            x = (l + r) // 2
        else:
            x = (l + r) / 2
        if func(x) == target:
            if side == "left":
                r=x
            else:
                l=x


        elif func(x) > target:
            r = x
        else:
            #print(r, l)
            l = x

    #print(l, r)
    if side == "left" and func(r) == target:
        return r
    elif side != "left" and func(l) == target:
        return l
    elif side == "left":
        return l
    else:
        return r


def nibutan_list(list_, target, side="left"):  # リストを二分探索
    if not isinstance(list_, list):
        list_ = list(list_)

    l = 0
    r = len(list_)
    x = (l + r) // 2
    while r-l > 1:
        x = (l+r)//2
        if list_[x] == target:
            return x
        elif list_[x] > target:
            r = x
        else:
            l = x

    if side == "left" or list_[x] == target:
        return l
    else:
        return r


class UfTree():
    def __init__(self, maxnum):
        self.parent = list(range(maxnum))
        self._size = [1] * maxnum
        self.rank = [0] * maxnum

    def size(self, a):
        return self._size[self.root(a)]

    def root(self, a):
        rank = 0
        cur = a
        while True:
            if self.parent[cur] == cur:
                #for i in path: # 経路圧縮
                #    self.parent[i] = cur
                return cur
            else:
                self.parent[cur] = self.parent[self.parent[cur]]
                cur = self.parent[cur]
                rank += 1

    def unite(self, a, b):
        ra = self.root(a)
        rb = self.root(b)
        if ra == rb:
            return self

        self._size[ra] += self._size[rb]
        self.parent[rb] = ra
        return self

if __name__ == "__main__":
    main()

Submission status: Accepted

Solution code:
n=int(input())
m=[]
for i in range(n-1):
    tmp=list(map(int,input().split()))
    m.append(tmp[0])
m.extend(list(map(int,input().split())))
dp=[[10**9]*n for i in range(n)]
for i in range(n):
    dp[i][i]=0
for W in range(1,n):
    for l in range(n-W):
        r=l+W
        for k in range(l,r+1):
            dp[l][r]=min(dp[l][r],m[l]*m[k]*m[r+1]+dp[l][k-1]+dp[k][r])
print(dp[0][n-1])

Submission status: Accepted

Solution code:
# https://onlinejudge.u-aizu.ac.jp/problems/ALDS1_10_B
import functools

INF = float('inf')
@functools.lru_cache(maxsize=None)
def rec(l, r):
    if l + 1 == r:
        return 0
    ret = INF
    for mid in range(l+1, r):
        ret = min(ret, rec(l, mid) + rec(mid, r)+R[l]*R[mid]*C[r-1])
    return ret


if __name__ == "__main__":
    N = int(input())
    R = []
    C = []
    for _ in range(N):
        r, c = list(map(int, input().split()))
        R.append(r)
        C.append(c)

    print(rec(0, N))

Submission status: Accepted

Solution code:
# 連鎖行列積 Matrix chain multiplication

n = int(input())
p = [-1 for i in range(n + 1)]
M = [[-1 for i in range(n + 1)] for i in range(n + 1)]

for i in range(1, n + 1):
    l, m = (int(i) for i in input().split())
    p[i - 1] = l
    p[i] = m

for i in range(1, n + 1):
    M[i][i] = 0

for l in range(2, n + 1):
    for i in range(1, n - l + 2):
        j = i + l - 1
        M[i][j] = 2000000000
        for k in range(i, j):
            M[i][j] = min(M[i][j], M[i][k] + M[k + 1][j] + p[i - 1] * p[k] * p[j])

print(M[1][n])

Submission status: Accepted

Solution code:
N = int(input())
matrices = [tuple(map(int, input().split())) for _ in range(N)]
R, C = zip(*matrices)
dp = [[float('inf')] * N for _ in range(N)]
for i in range(N): dp[i][i] = 0
for l in range(1, N):
    for i in range(N-l):
        r, c = R[i], C[i+l]
        dp[i][i+l] = min(r * C[j] * c + dp[i][j] + dp[j+1][i+l] for j in range(i, i+l))
print(dp[0][N-1])

Submission status: Accepted

Solution code:
INF = 1145141919810364364334

n = int(input())
p = []
for i in range(n):
    a,b = map(int,input().split())
    if i==0:
        p.append(a)
        p.append(b)
    else:
        p.append(b)
    
cost = [[INF] * (n+1) for i in range(n+1)]
for i in range(n+1):
    cost[i][i] = 0
    
for l in range(2,n+1):
    for i in range(1,n-l+2):
        j = i+l-1
        for k in range(i,j):
            cost[i][j] = min(cost[i][j] , cost[i][k] + cost[k+1][j] + p[i-1]*p[k]*p[j])
            
print(cost[1][n])

Submission status: Accepted

Solution code:
n=int(input())
a= [list(map(int, input().split())) for i in range(n)]
a+=a
# dp[i][j]=iからjまでの区間連鎖行列積
INF=10**12
dp=[[INF]*(2*n+1) for i in range(2*n+1)]
ans=0
for i in range(n):
    for l in range(2*n-i):
        r=i+l
        if l==r:
            dp[l][r]=0
        else:
            for k in range(l,r):
                dp[l][r]=min(dp[l][k]+dp[k+1][r]+a[l][0]*a[k][1]*a[r][1],dp[l][r])


print(dp[0][n-1])

Submission status: Accepted

Solution code:
N = int(input())
rc = [list(map(int, input().split())) for _ in range(N)]

DP = [[(0, -1, -1)]*(N) for _ in range(N)]
DP[0] = [(0, r, c) for r, c in rc]

for i in range(1, N):
    for j in range(N-i):
        lis = []
        for k in range(i):
            s, r, c = DP[k][j]
            s2, r2, c2 = DP[i-k-1][j+k+1]
            lis.append((r*c*c2+s+s2, r, c2))
        DP[i][j] = min(lis)
print(DP[-1][0][0])

Submission status: Accepted

Solution code:
def Matrix_Chain_Multiplication(M, p, N):
    
    for l in range(2, N + 1):
        for i in range(1, N - l + 1 + 1):
            j = i + l - 1

            M[i][j] = 500000000

            for k in range(i , j):
                M[i][j] = min(M[i][j], M[i][k] + M[k + 1][j] + p[i - 1] * p[k] * p[j])
    
    return M[1][N]

def Main():
    N = int(input())

    p = [0 for i in range(N+1)]
    M = [[0]*(N+1) for i in range(N+1) ] 

    i = 0
    for n in range(N):
        r, c = map(int, input().split())

        if n == 0:
            p[i] = r
            i += 1
            p[i] = c
            i += 1
        else:
            p[i] = c
            i += 1

    print(Matrix_Chain_Multiplication(M, p, N))

Main()

Submission status: Accepted

Solution code:
# Matrix Chain Multiplication
N, *A = map(int, open(0).read().split())
A = A[0::2]+[A[-1]]

INF = float('inf')
dp = [[INF]*(N) for _ in [0]*(N)]
# dp[i][j]: a_iからa_jまでの積に必要な最小の乗算回数

rg = range(N)

for i in rg:
    dp[i][i] = 0


for l in range(1, N):
    for i in rg:
        j = i + l
        if j >= N:
            continue
        for k in range(i, j):
            dp[i][j] = min(
                dp[i][j],
                dp[i][k] + dp[k+1][j] + A[i]*A[k+1]*A[j+1]
            )

print(dp[0][N-1])

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.buffer.readline
sys.setrecursionlimit(10 ** 7)

N = int(input())
RC = [list(map(int, input().split())) for _ in range(N)]

memo = [[-1] * (N + 1) for _ in range(N + 1)]
inf = 10**18


def mult(l, r):
    """
    半開区間[l, r)
    """
    if memo[l][r] != -1:
        return memo[l][r]
    if r - l <= 1:
        memo[l][r] = 0
        return 0

    res = inf
    for m in range(l + 1, r):
        prod = RC[l][0] * RC[m - 1][1] * RC[r - 1][1]
        tmp = mult(l, m) + mult(m, r) + prod
        res = min(res, tmp)
    memo[l][r] = res
    return res


ans = mult(0, N)
print(ans)

Submission status: Accepted

Solution code:
n = int(input())

r = [0] * n
c = [0] * n

for i in range(n):
    r[i], c[i] = map(int, input().split())

dp = [[float("inf")] * n for _ in range(n)]

for i in range(n):
    dp[i][i] = 0

for gap in range(1, n):
    for s in range(n):
        e = s + gap
        if e >= n:
            continue
        for k in range(s, e):
            dp[s][e] = min(dp[s][e], dp[s][k] + dp[k + 1][e] + r[s] * c[k] * c[e])

print(dp[0][n - 1])

Submission status: Accepted

Solution code:
def resolve():
    # cf. http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_10_B&lang=ja
    # http://agent.inf.kyushu-u.ac.jp/~yokoo/lecture/DA2_03.pdf
    def matrix_chain_multiplication(n):
        """
        連鎖行列積問題：
        n 個の行列について、行列 M_i の次元が与えられたとき、
        積 M_1 M_2...M_n の計算に必要なスカラー乗算の最小の回数を返す
        """
        m = [[0 for x in range(n + 1)] for y in range(n + 1)]
        for l in range(2, n + 1):
            for i in range(1, n - l + 2):
                j = i + l - 1
                m[i][j] = 99000001
                for k in range(i, j):
                    m[i][j] = min(m[i][j], m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j])
        return m[1][n]

    # M1からMnの行数と、Mnの列数を格納。
    # 積が定義されている以上型が合っているはずなのでその他は不要
    p = []

    # 行列の数n
    n = int(input())

    # 行列Mi(i=1...n)の次元r、c
    # rは行数、cは列数
    for i in range(n):
        listed_input = input().split()
        p.append(int(listed_input[0]))

    p.append(int(listed_input[1]))

    print(matrix_chain_multiplication(n))


resolve()

Submission status: Accepted

Solution code:
n = int(input())
RC = [list(map(int, input().split())) for _ in range(n)]
R = [RC[i][0] for i in range(n)]
C = [RC[i][1] for i in range(n)]

#n = 6
#R = [30, 35, 15, 5, 10, 20]
#C = [35, 15, 5, 10, 20, 25]

m = [[10**18]*(n+1) for _ in range(n+1)]
for i in range(n+1):
    m[i][i] = 0
    
for l in range(1, n):
    for i in range(1, n+1-l):
        m[i][i+l] = min([m[i][j] + m[j+1][i+l] + R[i-1]*C[j-1]*C[i+l-1] for j in range(i, i+l)])
        #print(i, i+l)
print(m[1][n])

Submission status: Accepted

Solution code:
import sys
import math
import string
import fractions
import random
from operator import itemgetter
import itertools
from collections import deque
import copy
import heapq
from bisect import bisect, bisect_left, bisect_right

MOD = 10 ** 9 + 7
INF = float('inf')
input = lambda: sys.stdin.readline().strip()

sys.setrecursionlimit(10 ** 8)

n = int(input())
row = []
column = []
for _ in range(n):
    r, c = map(int, input().split())
    row.append(r)
    column.append(c)

dp = [[INF] * (n + 10) for _ in range(n + 10)]

"""
dp[i][j] = iからj番目の行列積に必要なスカラー積の最小値
dp[i][j] = min(dp[i][k] + dp[k+1][j] + M[i].row * M[k].col * M[j].col)
"""

for i in range(n):  # 初期条件
    dp[i][i] = 0

for i in range(n, -1, -1):
    for j in range(i+1, n):
        for k in range(i, j):
            prod = row[i] * column[k] * column[j]
            dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + prod)
print(dp[0][n-1])

Submission status: Accepted

Solution code:
#!usr/bin/env python3
from collections import defaultdict,deque
from heapq import heappush, heappop
from itertools import permutations
import sys
import math
import bisect
def LI(): return [int(x) for x in sys.stdin.readline().split()]
def I(): return int(sys.stdin.readline())
def LS():return [list(x) for x in sys.stdin.readline().split()]
def S():
    res = list(sys.stdin.readline())
    if res[-1] == "\n":
        return res[:-1]
    return res
def IR(n):
    return [I() for i in range(n)]
def LIR(n):
    return [LI() for i in range(n)]
def SR(n):
    return [S() for i in range(n)]
def LSR(n):
    return [LS() for i in range(n)]

sys.setrecursionlimit(1000000)
mod = 1000000007

def solve():
    n = I()
    g = LIR(n)
    dp = [[float("inf")]*(n+1) for i in range(n)]
    for i in range(n):
        dp[i][i+1] = 0
    for k in range(1,n+1):
        for l in range(n):
            hl,wl = g[l]
            r = l+k
            if r > n:
                break
            hr,wr = g[r-1]
            nd = dp[l][r]
            for j in range(l+1,r):
                hj,wj = g[j-1]
                cost = hl*wj*wr
                nd = min(nd,dp[l][j]+dp[j][r]+cost)
            if nd < dp[l][r]:
                dp[l][r] = nd
    print(dp[0][n])
    return

#Solve
if __name__ == "__main__":
    solve()

Submission status: Accepted

Solution code:
def s():
 n=int(input())+1
 e=[input().split()for _  in[0]*~-n]
 p=[int(e[0][0])]+list(int(x[1])for x in e)
 m=[[0]*n for _ in[0]*n]
 for i in range(n):
  for r in range(n-i-1):
   c=r+i+1
   for j in range(r+1,c):
    x=m[r][j]+m[j][c]+p[r]*p[j]*p[c]
    if not 0<m[r][c]<=x:m[r][c]=x
 print(m[r][c])
if'__main__'==__name__:s()

Submission status: Accepted

Solution code:
import sys

# sys.stdin = open('input.txt')

N = 100 + 1

p = [0] * N
m = [[0] * N for _ in range(N)]

n = int(input())

for i in range(1, n+1):
    p[i-1], p[i] = map(int, input().split())
for i in range(1, n+1):
    m[i][i] = 0

for l in range(2, n+1):
    for i in range(1, n-l+1+1):
        j = i + l - 1
        m[i][j] = (1 << 21)
        for k in range(i, j-1+1):
            m[i][j] = min(m[i][j], m[i][k] + m[k+1][j] + p[i-1] * p[k] * p[j])

print(m[1][n])

Submission status: Accepted

Solution code:
def main():
    from functools import lru_cache
    import sys
    input=sys.stdin.readline
    sys.setrecursionlimit(100000000)
    INF=10**9
    n=int(input())
    M=[list(map(int,input().split())) for _ in range(n)]
   
    @lru_cache(maxsize=None)
    def dp(i,j):
        if i+1==j:
            return 0
        else:
            ans=INF
            for k in range(i+1,j):
                ans=min(ans,dp(i,k)+dp(k,j)+M[i][0]*M[k][0]*M[j-1][1])
            return ans
    print(dp(0,n))

if __name__=='__main__':
    main()

Submission status: Accepted

Solution code:
inf = float('inf')

n = int(input())

r = [0] * n         # 行数
c = [0] * n         # 列数

for i in range(n):
    ri, ci = map(int, input().split())
    r[i] = ri
    c[i] = ci

dp = [[0]*(n+1) for _ in range(n+1)]  # (n+1)*(n+1)のゼロ行列生成

for ls in range(2, n+1):        # 対象とする行列の数をlsとした。
    for i in range(n+1-ls):
        dp[i][i+ls] = inf
        for j in range(i+1, i+ls):  # 働きとしてはkに該当？
            dp[i][i+ls] = min(dp[i][i+ls], dp[i][j] + dp[j][i+ls] + r[i]*r[j]*c[i+ls-1])

ans = dp[0][n]

print(ans)

Submission status: Accepted

Solution code:
MAX = 10 ** 8
n = int(input())
M = [list(map(int,input().split())) for _ in range(n)]
dp = [[MAX for _ in range(n)] for _ in range(n)]
r = [0 for _ in range(n)] 
c = [0 for _ in range(n)] 

for i in range(n):
    r[i] = M[i][0]
    c[i] = M[i][1]
    dp[i][i] = 0

for d in range(1,n):
    for i in range(n-d):
        j = i + d
        min_v = MAX
        for k in range(i,j):
            v = r[i] * c[k] * c[j] + dp[i][k] + dp[k+1][j]
            min_v = min(min_v,v)

        dp[i][j] = min(dp[i][j], min_v)

print (dp[0][n-1])

Submission status: Accepted

Solution code:
if __name__ == '__main__':
    from sys import stdin
    input = stdin.readline

    N = 100
    p = [0]*(N+1)
    m = [[0]*(N+1) for _ in range(N+1)]

    n = int(input())
    for i in range(n):
        p[i], p[i+1] = map(int, input().split())

    for l in range(2, n+1):
        for i in range(1, n-l+2):
            j = i + l - 1
            m[i][j] = 2**21 # 十分大きい数
            for k in range(i, j):
                m[i][j] = min(m[i][j], m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j])

    print(m[1][n])

Submission status: Accepted

Solution code:
N = int(input())
P = []
for i in range(N):
	ta,tb = map(int ,input().split())
	if i == N-1:
		P.append(ta)
		P.append(tb)
	else:
		P.append(ta)
inf = float('inf')
dp = [[inf] * N for _ in range(N)]
for i in range(N):
	if i == N-1:
		dp[i][i] = 0
	else:
		dp[i][i] = 0
		dp[i][i+1] = P[i]*P[i+1]*P[i+2]

for right in range(2,N):
	for i in range(N):
		j = i + right
		if j > N-1:
			break

		for k in range(i,j):
			dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j]+P[i]*P[k+1]*P[j+1])

		

print(dp[0][N-1])

Submission status: Accepted

Solution code:
n = int(input())

M= [[] for i in range(n)]

for i in range(n):
  M[i] = list(map(int, input().split()))

p = [M[0][0]]

for i in range(n):
  p.append(M[i][1])

f_inf = float("inf")

m = [[f_inf for i in range(n)] for j in range(n)]

def matrixChainOrder(n):
  for i in range(n):
    m[i][i] = 0
  for l in range(2, n+1):
    for i in range(n-l+1):
      j = i + l - 1
      for k in range(i, j):
        q = m[i][k] + m[k+1][j] + p[i]*p[k+1]*p[j+1]
        if q < m[i][j]:
          m[i][j] = q

matrixChainOrder(n)

print(m[0][n-1])

Submission status: Accepted

Solution code:
def main():
    """連鎖行列積を求める.    
    """
    n = int(input())
    inf = 10**10
    if n == 0 or n == 1:
        print(0)
        return
    if n > 1:
        p = [int(input().split()[0]) for _ in range(n-1)]
    p.extend(list(map(int, input().split())))
    m = [[inf*(i!=j) for i in range(n)] for j in range(n)]
    for l in range(1, n):
        for i in range(n-l):
            j = i+l
            for k in range(i, j):
                m[i][j] = min(m[i][j], m[i][k] + m[k+1][j] + p[i]*p[k+1]*p[j+1])
    print(m[0][-1])

if __name__ == "__main__":
    main()

Submission status: Accepted

Solution code:
N = int(input())
for i in range(N):
    if i == 0:
        P = list(map(int, input().split()))
        continue
    P.append(int(input().split()[1]))

# dpテーブルの用意 minを取るときはinf埋めしておくと処理が楽になるしバグが見つかりやすい
INF = 2**32-1
dp = [[INF]*N for _ in range(N)]

# dpテーブルの初期化
# 対角成分0
for ij in range(N):
    dp[ij][ij] = 0
    
for l in range(1, N):
    for i in range(N-l):
        j = i+l
        for k in range(i,j):
            dp[i][j] = min(dp[i][k] + dp[k+1][j] + P[i]* P[j+1]*P[k+1], dp[i][j])
print(dp[0][-1])