题目大意
给定一个具有 (n) 个顶点的凸多边形,将顶点从 (1) 至 (n) 标号,顶点 (i) 的权值为一个正整数 (a_i) 。将这个凸多边形划分成 (n-2) 个互不相交的三角形,试求这些三角形顶点的权值乘积和至少为多少。
其中, (3 leq n leq 50) , (1 leq a_i < 10^9) 。
题解
设 (f(i,j)) 表示点 (i,i+1,i+2,...j) 组成的凸多边形内进行划分的最小权值乘积和。
则 (f(i,j) = minlimits_{i < k < j} left{f(i,k) + f(k,j) + a_i a_k a_j
ight})
如下图:
也就是划分出粉色三角形,并合并蓝色多边形的贡献 。
但如果连接 (ik) 不是最优的呢?其实不连接的情况也可以转移出来,画个图就知道了。(然而自己当时想了30min,一直怀疑这样做的可行性)
所以我们设计状态的时候,当我们觉得某种情况无法转移出来时,要仔细想想是否能从别的情况得到,而不是轻易否定这种状态设计。
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::memset;
using std::min;
using std::max;
#define MAX_N (50 + 5)
struct Big_Number
{
int bit[35];
int len;
Big_Number()
{
memset(bit, 0, sizeof bit);
len = 1;
}
Big_Number operator = (int num)
{
memset(bit, 0, sizeof bit);
len = 0;
do
{
bit[++len] = num % 10;
num /= 10;
}
while (num);
return *this;
}
bool operator < (const Big_Number & x) const
{
if (len != x.len) return len < x.len;
for (int i = len; i; --i)
{
if (bit[i] != x.bit[i]) return bit[i] < x.bit[i];
}
return false;
}
Big_Number operator + (const Big_Number & x) const
{
Big_Number res;
res.len = max(len, x.len);
for (int i = 1; i <= res.len; ++i)
{
res.bit[i] += bit[i] + x.bit[i];
if (res.bit[i] >= 10)
{
++res.bit[i + 1];
res.bit[i] -= 10;
}
}
while (res.bit[res.len + 1])
{
++res.len;
if (res.bit[res.len] >= 10)
{
++res.bit[res.len + 1];
res.bit[res.len] -= 10;
}
}
return res;
}
Big_Number operator * (const Big_Number & x) const
{
Big_Number res;
res.len = len + x.len - 1;
for (int i = 1; i <= res.len; ++i)
{
for (int j = min(i, len); j; --j)
{
res.bit[i] += bit[j] * x.bit[i - j + 1];
}
if (res.bit[i] >= 10)
{
res.bit[i + 1] += res.bit[i] / 10;
res.bit[i] %= 10;
}
}
while (res.bit[res.len + 1])
{
++res.len;
if (res.bit[res.len] >= 10)
{
res.bit[res.len + 1] += res.bit[res.len] / 10;
res.bit[res.len] %= 10;
}
}
return res;
}
};
int n;
Big_Number a[MAX_N];
Big_Number f[MAX_N][MAX_N];
Big_Number Min(Big_Number x, Big_Number y)
{
if (x < y) return x;
return y;
}
int main()
{
scanf("%d", &n);
int tmp;
for (int i = 1; i <= n; ++i)
{
scanf("%d", &tmp);
a[i] = tmp;
}
for (int i = n - 2; i; --i)
{
for (int j = i + 2; j <= n; ++j)
{
f[i][j].len = 30;
memset(f[i][j].bit, 0x7f, sizeof f[i][j].bit);
for (int k = i + 1; k < j; ++k)
{
f[i][j] = Min(f[i][j], f[i][k] + f[k][j] + a[i] * a[k] * a[j]);
}
}
}
for (int i = f[1][n].len; i; --i)
{
printf("%d", f[1][n].bit[i]);
}
return 0;
}