//
// 有N堆(N<=100)石子围成一圈, 每堆石子数量,现要将石子有序的合并成一堆,规定如下:每次只能合并相邻的2堆石子,合并花费为新合成的一堆石子的数量。求将这N堆石子合并成一堆的总花费最小(或最大)。
//
// 状态转移方程dp[i][j] = min(dp[i][k]+[(i+k+1)%n][j-k-1]+sum[i][j])
// 把要合并的j堆分成前k堆和后j-k-1堆以及最后一堆i+j
// 有N堆(N<=100)石子围成一圈, 每堆石子数量,现要将石子有序的合并成一堆,规定如下:每次只能合并相邻的2堆石子,合并花费为新合成的一堆石子的数量。求将这N堆石子合并成一堆的总花费最小(或最大)。
//
// 状态转移方程dp[i][j] = min(dp[i][k]+[(i+k+1)%n][j-k-1]+sum[i][j])
// 把要合并的j堆分成前k堆和后j-k-1堆以及最后一堆i+j
//input:
//3
//4
//4 5 9 4
//6
//3 4 6 5 4 2
//10
//9 3 2 8 5 10 3 13 2 4
//output
//Case #1: 43 54
//Case #2: 61 91
//Case #3: 188 368
//3
//4
//4 5 9 4
//6
//3 4 6 5 4 2
//10
//9 3 2 8 5 10 3 13 2 4
//output
//Case #1: 43 54
//Case #2: 61 91
//Case #3: 188 368
#include <stdio.h>
static const int MAX_N = 105;
static const int INF = 1 << 30;
static const int INF = 1 << 30;
int n; // number of piles
int piles[MAX_N];
int piles[MAX_N];
int mins[MAX_N][MAX_N]; // i是堆的编号,0<=i<n, 从第i堆开始合并后面j个堆的最小花费。
int maxs[MAX_N][MAX_N];
int maxs[MAX_N][MAX_N];
int min(int a, int b)
{
return a < b ? a : b;
}
int max(int a, int b)
{
return a > b ? a : b;
}
{
return a > b ? a : b;
}
// 计算从编号为start的堆开始,统计length个堆的总和
int getSum(int start, int length)
{
int sum = piles[start];
for (int i = 1; i <= length; i++)
{
int j = (start+i)%n;
sum += piles[j];
}
int getSum(int start, int length)
{
int sum = piles[start];
for (int i = 1; i <= length; i++)
{
int j = (start+i)%n;
sum += piles[j];
}
return sum;
}
}
int solve()
{
int i, j, k;
// j为0时,没有合并动作,花费为0
for (i = 0; i <= n - 1; i++)
{
mins[i][0] = 0;
maxs[i][0] = 0;
}
// want the merge j piles with ith pile. 1<=j<=n-1
for (j = 1; j <= n - 1; j++)
{
// start from ith pile
for (i = 0; i <= n-1; i++)
{
// let the mins[i][j] is INF
mins[i][j] = INF;
maxs[i][j] = 0;
//printf("sum[%d][%d]=%d\n", i, j, getSum(i, j));
// k is the subset of j, that is 0~j-1
for (k = 0; k <= j - 1; k++)
{
//printf("i:%d j:%d k:%d i+k+1:%d j-k-1:%d\n", i, j, k, (i + k + 1)%n, (j - k - 1));
mins[i][j] = min(mins[i][j], mins[i][k] + mins[(i+k+1)%n][j-k-1]+getSum(i, j));
maxs[i][j] = max(maxs[i][j], maxs[i][k] + maxs[(i + k + 1) % n][j - k - 1] + getSum(i, j));
}
//printf("min[%d][%d]=%d\n", i, j, mins[i][j]);
}
//printf("-------------------------------\n");
}
return 0;
}
{
int i, j, k;
// j为0时,没有合并动作,花费为0
for (i = 0; i <= n - 1; i++)
{
mins[i][0] = 0;
maxs[i][0] = 0;
}
// want the merge j piles with ith pile. 1<=j<=n-1
for (j = 1; j <= n - 1; j++)
{
// start from ith pile
for (i = 0; i <= n-1; i++)
{
// let the mins[i][j] is INF
mins[i][j] = INF;
maxs[i][j] = 0;
//printf("sum[%d][%d]=%d\n", i, j, getSum(i, j));
// k is the subset of j, that is 0~j-1
for (k = 0; k <= j - 1; k++)
{
//printf("i:%d j:%d k:%d i+k+1:%d j-k-1:%d\n", i, j, k, (i + k + 1)%n, (j - k - 1));
mins[i][j] = min(mins[i][j], mins[i][k] + mins[(i+k+1)%n][j-k-1]+getSum(i, j));
maxs[i][j] = max(maxs[i][j], maxs[i][k] + maxs[(i + k + 1) % n][j - k - 1] + getSum(i, j));
}
//printf("min[%d][%d]=%d\n", i, j, mins[i][j]);
}
//printf("-------------------------------\n");
}
return 0;
}
int main()
{
freopen("stone1_input.txt", "r", stdin);
int T;
scanf("%d", &T);
int tc;
for (tc = 1; tc <= T; tc++)
{
{
freopen("stone1_input.txt", "r", stdin);
int T;
scanf("%d", &T);
int tc;
for (tc = 1; tc <= T; tc++)
{
scanf("%d", &n);
int i;
for (i = 0; i < n; i++)
{
scanf("%d", &piles[i]);
}
int minval = INF;
int maxval = 0;
int i;
for (i = 0; i < n; i++)
{
scanf("%d", &piles[i]);
}
int minval = INF;
int maxval = 0;
solve();
for (i = 0; i < n; i++)
{
if (minval > mins[i][n - 1])
minval = mins[i][n - 1];
if (maxval < maxs[i][n - 1])
maxval = maxs[i][n - 1];
}
printf("Case #%d: %d %d\n", tc, minval, maxval);
}
return 0;
}
{
if (minval > mins[i][n - 1])
minval = mins[i][n - 1];
if (maxval < maxs[i][n - 1])
maxval = maxs[i][n - 1];
}
printf("Case #%d: %d %d\n", tc, minval, maxval);
}
return 0;
}