限制条件:
- 分为N-2个三角形
- 互不相交
分析:
由于一个三角形是需要三个顶点,我们可以先枚举三个顶点,然后观察一下有什么性质
如图,当我们枚举出i,j,k三个顶点的时候,当前可以划分为三个集合
- 左边的多边形集合+右边的多边形集合+当前的三角形
这样子看就和能量项链很像了,通过枚举三个点,然后计算集合,由于需要先计算出所有的单个三角形的集合 然后 再递推到一整个多边形中的权值(枚举两个端点,至少中间间隔一个点,所以len为3,才能保证中间间隔至少一个点)
所以len至多从3开始枚举,由于有n个顶点,至多n边形,所以枚举到n,3<=len<=n
我们发现,由于不同的三角形之间不能相交,那么对于一个多边形集合来说
状态表示:所有由(i,i+1),(i+1,i+2)...(j-1,j)构成的多边形划分的三角形的集合
子集划分/状态计算:当前dp[i][j]可以划分为三个子集=左边的多边形集合+当前三角形+右边多边形集合,dp[i][j]=dp[i][k]+dp[k][j]+w[i]*w[i]*w[k],根据中断点k的不同可以划分为多个子集
- 选择i+1作为中断点
- ...
- 选择j-1作为中断点
递推顺序:3<=len<=n
初始化:无穷大
边界:dp[i][i]=dp[i][i+1]=0
由于需要高精度,所以这里用vector使用高精度
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int N = 55;
vector<int> dp[N][N];
int w[N];
typedef long long ll;
vector<int> init(ll a)
{
if (a == (long long)1e18)
{
vector<int> res(35, 0);
res.push_back(1);
reverse(res.begin(), res.end());
return res;
}
vector<int> res;
while (a)
{
res.push_back(a % 10);
a /= 10;
}
reverse(res.begin(), res.end());
return res;
}
vector<int> add(vector<int> a, vector<int> b)
{
vector<int> c;
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
int t = 0;
for (int i = 0;i < a.size() || i < b.size();i++)
{
if (i < a.size())
t += a[i];
if (i < b.size())
t += b[i];
c.push_back(t % 10);
t /= 10;
}
if (t)
c.push_back(t);
reverse(c.begin(), c.end());
return c;
}
vector<int> mul(vector<int> a, ll r)
{
vector<int> c;
reverse(a.begin(), a.end());
ll t = 0;
for (int i = 0;i < a.size() || t;i++)
{
if (i < a.size())
t += a[i] * r;
c.push_back(t % 10);
t /= 10;
}
while (c.back() == 0 && c.size() > 1) c.pop_back();
reverse(c.begin(), c.end());
return c;
}
bool cmp(vector<int>& a, vector<int>& b)
{
if (a.size() != b.size())
return a.size() < b.size();
else
for (int i = 0;i < a.size();i++)
if (a[i] != b[i])
return a[i] < b[i];
return false;
}
int main()
{
int n;
cin >> n;
for (int i = 1;i <= n;i++)
cin >> w[i];
for (int i = 1;i <= n;i++)
for (int j = 1;j <= n;j++)
dp[i][j] = init((long long)1e18);
for (int len = 1;len <= n;len++)
for (int i = 1;i + len - 1 <= n;i++)
{
int j = i + len - 1;
if (len == 1 || len == 2) dp[i][j] = init(0);
else
for (int k = i + 1;k < j;k++)
{
auto temp = add(dp[i][k], dp[k][j]);
auto t = mul(mul(init(w[i]), w[j]), w[k]);
temp = add(temp, t);
if (cmp(temp,dp[i][j]))
dp[i][j] = temp;
}
}
for (auto t : dp[1][n])
cout << t;
return 0;
}