Problem:
カード
正の整数が書かれた一組のカードがあります。カードを積んで山をいくつか作り、それらを横一列に並べます。その中から隣り合った 2 つのカードの山を選び、右側の山の上に左側の山をそのまま重ねます。この操作をカードの山が一つになるまで繰り返していきます。
2 つのカードの山を重ねる時にそれらの一番上と下のカードに書かれた数をすべて掛け合わせます。こうして得られた数をカードの重ね合わせのコストと呼ぶことにします。カードの山を一つにするためのコストはすべての重ね合わせのコストを足し合わせたものとします。
どのような順番でカードの山を重ねるかでコストは変わります。たとえば、3 つのカードの山がある場合を考えます。それらの一番上と下のカードに書かれた数が，左側の山から順にそれぞれ 3 と 5, 2 と 8, 5 と4 だったとします。このとき，はじめに左と真ん中の山を重ねたときのコストは、3 × 5 × 2 × 8 = 240 です。この重ね合わせによって、一番上のカードが 3 で一番下のカードが 8 である山ができます。
この山を右の山の上に重ねると、そのコストは 3 × 8 × 5 × 4 = 480 になります。したがって、この順番でカードの山を一つにまとめたときのコストは 240 + 480 = 720 です。（図1）
一方、はじめに真ん中と右の山を重ねてから最後に左の山を重ねることにすると、そのときのコストは 2 × 8 × 5 × 4 + 3 × 5 × 2 × 4 = 440 になります。したがって，後の場合のように重ねた方がコストが小さくなります。（図2）
カードの山の個数とそれぞれの山の一番上と下のカードに書かれた数を入力とし、カードの山を一つにまとめるのに必要な最小のコストを出力するプログラムを作成してください。ただし、山の個数は 100 個以下とし、入力されるデータはどのような順番でコストを計算しても 2
31
-1 を超えることはありません。
Input
入力は以下の形式で与えられます。
n
a
1
b
1
a
2
b
2
:
a
n
b
n
1 行目にカードの山の個数
n
(
n
≤ 100)、続く
n
行に左から
i
番目の山の 1 番上のカードに書かれた数
a
i
(1 ≤
a
i
≤ 200) と 1 番下のカードに書かれた数
b
i
(1 ≤
b
i
≤ 200) が与えられます。
Output
カードの山を一つにまとめるのに必要な最小のコストを１行に出力してください。
Sample Input
3
3 5
2 8
5 4
Output for the Sample Input
440

Submitted solutions:

code_snippet: #include<iostream>
#include<algorithm>
using namespace std;
#define INF 2147483647
int dp[120][120];
int n,a[120],b[120];
int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i]>>b[i];
	}
	for(int i=0;i<n;i++){
		dp[i][i]=0;
		for(int j=0;j<n;j++){
			if(i!=j)dp[i][j]=INF;
		}
	}
	for(int i=0;i<=n;i++){
		for(int j=0;j<n;j++){
			for(int k=0;k<n;k++){
				for(int l=j;l<=k-1;l++){
					if(dp[j][l]==INF || dp[l+1][k]==INF)continue;
					int S=dp[j][l]+dp[l+1][k];
					dp[j][k]=min(dp[j][k],S+a[j]*b[l]*a[l+1]*b[k]);
				}
			}
		}
	}
	cout<<dp[0][n-1]<<endl;
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 1196
final_rank: 3

code_snippet: #include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#include <algorithm>
#include <set>

#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define REP(i,j) FOR(i,0,j)
#define mp std::make_pair

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int,int> P;
typedef std::pair<int,P> State;

const int INF = 1001001001;

// S N E W(南北東西)
const int dx[8] = {0, 0, 1, -1, 1, 1, -1, -1}, dy[8] = {1, -1, 0, 0, 1, -1, 1, -1};

struct Deck{
    int first, last;
};

Deck ds[100];
// dp[i][j][k] := 位置iからj個とk個の山に分ける時の最小値
int dp[100][101][101];

int rec(int pos, int a, int b){
    if(dp[pos][a][b] != -1){
        return dp[pos][a][b];
    }

    if(a == 0 || b == 0){
        return 0;
    }

    int res = ds[pos].first * ds[pos+a-1].last * ds[pos+a].first * ds[pos+a+b-1].last;
    // printf("%d, %d, %d: %d\n", pos, a, b, res);
    if(a == 1 && b == 1){
        return res;
    }

    int min_a = rec(pos, 1, a-1);
    FOR(i, 2, a){
        min_a = std::min(rec(pos, i, a-i), min_a);
    }

    int min_b = rec(pos+a, 1, b-1);
    FOR(i, 2, b){
        min_b = std::min(rec(pos+a, i, b-i), min_b);
    }

    res += min_a + min_b;
    return dp[pos][a][b] = res;
}

int main(){
    int N;
    std::cin >> N;
    
    REP(i, N){
        std::cin >> ds[i].first >> ds[i].last;
    }
    std::fill(dp[0][0], dp[0][0]+100*101*101, -1);
    
    int res = rec(0, 1, N-1);
    FOR(i, 2, N){
        res = std::min(rec(0, i, N-i), res);
    }

    std::cout << res << std::endl;
}
accuracy: 1
time_ms: 20
memory_kb: 5148
final_rank: 4

code_snippet: #include<stdio.h>
#include<vector>
#include<stdlib.h>
#include <string.h>
struct Yama{
	int a,b;
};
std::vector<Yama> yamas;
int ans[101][101];

int calc(int n){
	memset(ans,-1,sizeof(ans));
	for(int i=0;i<n;i++)ans[i][i]=0;
	for(int i=1;i<n;i++){
		for(int j=0;j<n-1;j++){
			for(int k=j;k<n-1;k++){
				if(ans[j][k]==-1)break;
				for(int l=k+1;l<n&&(l-k)<=i;l++){
					if(ans[k+1][l]==-1)continue;
					int temp=ans[j][k]+yamas[j].a*yamas[k].b*yamas[k+1].a*yamas[l].b+ans[k+1][l];
					if(ans[j][l]==-1 || temp<ans[j][l])ans[j][l]=temp;
				}
			}
		}
	}

	return ans[0][n-1];
}


int main(){
	int n;
	
	Yama yama;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d %d",&yama.a,&yama.b);
		yamas.push_back(yama);
	}
	
	printf("%d\n",calc(n));
}
accuracy: 1
time_ms: 10
memory_kb: 1088
final_rank: 1

code_snippet: #include<stdio.h>
#include<vector>
#include<stdlib.h>
#include <string.h>
struct Yama{
	int a,b;
};
std::vector<Yama> yamas;
int ans[101][101],nextAns[101][101];

int calc(int n){
	memset(ans,-1,sizeof(ans));
	for(int i=0;i<n;i++)ans[i][i]=0;
	memcpy(nextAns,ans,sizeof(nextAns));
	for(int i=1;i<n;i++){
		for(int j=0;j<n-1;j++){
			for(int k=j;k<n-1;k++){
				if(ans[j][k]==-1)continue;
				for(int l=k+1;l<n&&(l-k)<=i;l++){
					if(ans[k+1][l]==-1)continue;
					int temp=ans[j][k]+yamas[j].a*yamas[k].b*yamas[k+1].a*yamas[l].b+ans[k+1][l];
					if(ans[j][l]==-1 || temp<nextAns[j][l])nextAns[j][l]=temp;
				}
			}
		}
		memcpy(ans,nextAns,sizeof(nextAns));
	}

	return ans[0][n-1];
}


int main(){
	int n;
	
	Yama yama;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d %d",&yama.a,&yama.b);
		yamas.push_back(yama);
	}
	
	printf("%d\n",calc(n));
}
accuracy: 1
time_ms: 20
memory_kb: 1144
final_rank: 2