Go: package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"strconv"
)

var cache [100][100]int

func main() {
	sc := bufio.NewScanner(os.Stdin)
	sc.Split(bufio.ScanWords)
	sc.Scan()
	num, _ := strconv.Atoi(sc.Text())
	tables := []table{}
	for i := 0; i < num; i++ {
		sc.Scan()
		num1, _ := strconv.Atoi(sc.Text())
		sc.Scan()
		num2, _ := strconv.Atoi(sc.Text())
		t := table{num1, num2}
		tables = append(tables, t)
	}

	fmt.Println(minimum(0, len(tables)-1, tables))
}

type table struct {
	v int
	h int
}

func minimum(i int, j int, t []table) int {
	if i == j {
		return 0
	}

	// fmt.Printf("i:%v j:%v\n", i, j)
	if cache[i][j] != 0 {
		return cache[i][j]
	}

	min := math.MaxInt64
	for k := i; k < j; k++ {
		p := t[i].v
		n := t[k].h
		q := t[j].h
		val := minimum(i, k, t) + minimum(k+1, j, t) + p*n*q
		if val < min {
			min = val
		}
	}

	cache[i][j] = min
	return min
}

C++: #include <stack>
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <string>
#include <limits>
using namespace std;
int gcd(int a, int b)
{
   if (a%b == 0)
   {
       return(b);
   }
   else
   {
       return(gcd(b, a%b));
   }
}
int mod = 1000000000 + 7;
vector<int> v;
class Calc
{
    // 宣言
    long long a;

    public:
        // 素因数分解
        void decompositPrime(long long a);
};

/*
 * 素因数分解
 */
void Calc::decompositPrime(long long n)
{
    // 割る数の初期値
    a = 2;
    // √n ≧ a ( n ≧ a * a ) の間ループ処理
    while (n >= a * a) {
        // a で割り切れたら、a は素因数
        // そして、割られる数を a で割る
        // a で割り切れなかったら、 a を 1 増加させる
        if (n % a == 0) {
            //printf("%d * ", a);
             v.push_back(a);
            n /= a;
        } else {
            a++;
        }
    }
    // 最後に残った n は素因数
    v.push_back(n);
    //printf("%d\n", n);
}

int main(){
    //std::stack<int> stack;
    int n;
    cin >> n;
    long ans = 0;
    vector<int> a(n+1);
    for(int i = 0; i < n; i++){
        cin >> a[i] >> a[i+1];
    }
    long mat[n+1][n+1];
    for(int i = 1; i <= n; i++){
        mat[i][i] = 0;
    }
    for(int L = 2; L <= n; L++){
        for(int i = 1; i <= n-L+1; i++){
            int j = i+L-1;
            mat[i][j] = numeric_limits<long>::max();
            for(int k = i; k < j; k++){
                mat[i][j] = min(mat[i][j], mat[i][k] + mat[k+1][j] + a[i-1]*a[k]*a[j]);
            }
        }
    }
    cout << mat[1][n] << endl;
    return 0;
}

C++: #include <iostream>
#include <iomanip>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <cstdio>
#include <utility>
#include <string>
#include <cmath>
#include <cstdlib>
#include <cstring>

using namespace std;

typedef uint64_t u64;
typedef int64_t s64;
typedef uint32_t u32;
typedef int32_t s32;
typedef vector<s32> vs32;
typedef vector<u32> vu32;
typedef vector<s64> vs64;
typedef vector<u64> vu64;

const double PI=3.14159265358979323846;

#define MAX(x, y) ((x) < (y) ? (y) : (x))
#define MIN(x, y) ((x) > (y) ? (y) : (x))

#define rep(i, N) for(int i = 0; i < N; ++i)

#define CEIL(x, y) (((x) + (y) - 1) / (y))
#define MOD 1000000007ULL

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    int n;
    cin >> n;

    vs32 p(n + 1);
    rep (i, n)
    {
        cin >> p[i] >> p[i + 1];
    }

    vector< vs32 > dp(n + 1, vs32(n + 1, 0));
    for (int l = 2; l <= n; ++l)
    {
        for (int i = 1; i <= n  - l + 1; ++i)
        {
            dp[i][i] = 0;
            int j = i + l - 1;
            dp[i][j] = 1e9;
            for (int k = i; k < j; ++k)
            {
                dp[i][j] = MIN(dp[i][j], dp[i][k] + dp[k + 1][j] + p[i - 1] * p[k] * p[j]);
            }
        }
    }

    cout << dp[1][n] << "\n";
    return 0;
}

C++: #include <cstdio>
#include <vector>

using namespace std;

using i64=long long;

const i64 INF=1LL<<61;

int main() {
    size_t n;
    scanf("%zu", &n);

    vector<int> r(n), c(n);
    for (size_t i=0; i<n; ++i)
        scanf("%d %d", &r[i], &c[i]);

    vector<vector<i64>> dp(n, vector<i64>(n, INF));
    for (size_t i=0; i<n; ++i) dp[i][i] = 0;

    for (size_t k=1; k<n; ++k)
        for (size_t i=0; i+k<n; ++i) {
            size_t j=i+k;
            for (size_t m=i; m<j; ++m) {
                i64 tmp=dp[i][m]+dp[m+1][j]+r[i]*c[j]*c[m];
                if (dp[i][j] > tmp)
                    dp[i][j] = tmp;
            }
        }

    printf("%lld\n", dp[0][n-1]);
    return 0;
}

C++: #include <iostream>
using ll = long long;
using namespace std;

/* initialize */

/* main */
int main() {
    int n, p[101], m[101][101];
    cin >> n;
    for (int i = 0; i < n; ++i) {
        cin >> p[i] >> p[i+1];
    }
    for (int i = 1; i <= n; ++i) m[i][i] = 0;
    for (int l = 2; l <= n; ++l) {
        for (int i = 1; i <= n-l+1; ++i) {
            int j = i+l-1;
            m[i][j] = 1 << 21;
            for (int k = i; k <=j-1; ++k) {
                m[i][j] = min(m[i][j] , m[i][k]+m[k+1][j] +p[i-1]*p[k]*p[j]);
            }
        }
    }
    cout << m[1][n] << "\n";
    return 0;
}

C++: /**
 * 	matrix chain multiplication
 * 	f(n,m) = multiply Mn*M(n+1)*...*M(m-1)*M(m)
 * 	f(n,n) = 1
 * 	r(n)=c(n-1)
 * 	f(n,n+1) = C(n) * R(n) * C(n+1) = c(n) * c(n-1) * c(n+1)
 * 	f(n,k,m) = f(n,k)*f(k+1,m)*C(n)*r(n)*c(k)
 * 	f(n,m) = min(f(n,k,m)
 */

#include <iostream>
#include <cmath>
#include <climits>

using namespace std;

int r[45] = {0};
int a[100][100] = {0};

int f(int n, int m);
int f(int n, int k, int m);


int f(int n, int k, int m)
{
	return f(n,k) * f(k+1,m) + (r[n] * r[k+1] * r[m+1]);
}

int f(int n, int m)
{
	if (n==m) return 1;
	int & ra = a[n][m];
	if (ra) return ra;
	ra = INT_MAX;
	for (int k=n;k<m;k++)
	{
		int ans = f(n,k,m);
		if (ans < ra) ra = ans;
	}
	return ra;
}

int main()
{
	int rr = 0;
	int cc = 0;
	int n = 0;
	cin >> n;
	for (int i=0;i<n;i++)
	{
		cin >> rr >> cc;
		r[i]=rr;
		r[i+1]=cc;
	}
	for (int i=0;i<n-1;i++)
	{
		a[i][i+1] = r[i] * r[i+1] * r[i+2];
	}
	int ans = f(0,n-1);
	cout << ans << endl;
}

C++: #include <iostream>
#include <cstdio>
#include <map>
#define MAX_NUM 100
#define INFTY 1000000000

using namespace std;

//think easy make easy

int n;//num of input


pair<int,int> MatrixChain[MAX_NUM+1];

int calc(int s,int e){//s~eの連鎖行列積の最少計算回数を出力
	int min_time  = INFTY;

	int min_tmp;
	if(s == e){
		return 0;
	}
	for(int i=s;i<e;i++){
		min_tmp = calc(s,i) + calc(i+1,e) 
			+MatrixChain[s].first*MatrixChain[i].second*MatrixChain[e].second;
		if(min_tmp < min_time)
			min_time = min_tmp;
	}
	return min_time;
}

int main(){
	scanf("%d",&n);
	int r,c;//row,column

	for(int i=0;i<n;i++){
		scanf("%d %d",&r,&c);
		MatrixChain[i] = pair<int,int>(r,c);//i:1~n-1
	}

	cout <<calc(0,n-1);

	return 0;
}

C++: #include <iostream>
#include <cstdio>
#include <map>
#define MAX_NUM 100
#define INFTY 1000000000
#define NIL -1

using namespace std;

//think easy make easy

int n;//num of input


pair<int,int> MatrixChain[MAX_NUM+1];
map<pair<int,int>,int> mapMC;

int calc(int s,int e){//s~eの連鎖行列積の最少計算回数を出力
	int min_time  = INFTY;
	int min_tmp;

	if(mapMC[pair<int,int>(s,e)] != NIL)
		return mapMC[pair<int,int>(s,e)];

	if(s == e){
		return 0;
	}
	for(int i=s;i<e;i++){
		min_tmp = calc(s,i) + calc(i+1,e) 
			+MatrixChain[s].first*MatrixChain[i].second*MatrixChain[e].second;
		if(min_tmp < min_time)
			min_time = min_tmp;
	}
	mapMC[pair<int,int>(s,e)] = min_time;//メモ
	return min_time;
}

int main(){
	scanf("%d",&n);
	int r,c;//row,column

	for(int i=0;i<n;i++){
		scanf("%d %d",&r,&c);
		MatrixChain[i] = pair<int,int>(r,c);//i:1~n-1
	}
	for(int i=0;i<n;i++){
		for(int j=i;j<n;j++){
			mapMC[pair<int,int>(i,j)] = NIL;
		}
	}

	cout <<calc(0,n-1) <<endl;

	return 0;
}