『题目』:
给定
N
N
N,想象一个凸
N
N
N 边多边形,其顶点按顺时针顺序依次标记为
A
[
0
]
,
A
[
i
]
,
.
.
.
,
A
[
N
−
1
]
A[0], A[i], ..., A[N-1]
A[0],A[i],...,A[N−1]。
假设您将多边形剖分为
N
−
2
N-2
N−2 个三角形。对于每个三角形,该三角形的值是顶点标记的乘积,三角剖分的分数是进行三角剖分后所有
N
−
2
N-2
N−2 个三角形的值之和。
返回多边形进行三角剖分后可以得到的最低分。
『输入输出』:
输入 | 输出 |
---|---|
[1,2,3] | 6 |
[3,7,4,5] | 144 |
[1,3,1,4,1,5] | 13 |
『题解』:
这道题比较难想象的是这个dp的规则,因为图是一个环,所以dp不好处理,首先要知道
N
−
2
N-2
N−2 条边能保证某一条边肯定会落在某一个三角形上面,如下面图边
[
0
,
1
]
[0,1]
[0,1]所示,从边
[
0
,
1
]
[0,1]
[0,1]出发选一个顶点
k
k
k,这里的
k
=
3
k=3
k=3,所以就可以将图继续切分成两个子图进行递归求解。从而可以推出公式,其中
d
p
(
l
,
r
)
dp(l,r)
dp(l,r) 代表以从
l
l
l 到
r
r
r 的多边形,以
[
l
,
r
]
[l,r]
[l,r]为底边。
d
p
(
l
,
r
)
=
{
0
if
(
r
−
l
)
<
2
m
i
n
(
d
p
(
l
,
k
)
+
d
p
(
k
,
r
)
+
V
l
k
r
)
if
l
<
k
<
r
,
k
=
l
+
1...
r
−
1
dp(l,r)= \begin{cases} 0 & \text {if $(r-l) \lt 2$} \\ min(dp(l,k)+dp(k,r)+V_{lkr}) & \text{if $l \lt k \lt r$},k=l+1...r-1 \end{cases}
dp(l,r)={0min(dp(l,k)+dp(k,r)+Vlkr)if (r−l)<2if l<k<r,k=l+1...r−1
『实现』:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
/**
* Author:
* Gavinjou大笨象
* Date:
* 2019-05-06
* Description:
* 三角最优子结构
*/
int N;
//当钱所选的边是a,剩下还要选的条数
int dp[55][55];
int valueA[55];
int flag[55];
int Min(int a , int b)
{
if(a < b) return a;
return b;
}
int deep(int *A,int l,int r)
{
//答案值为无穷大
int ans = -1;
//如果没办法组成三角型,答案返回的值为0
if(r - l < 2) return 0;
//返回记忆值
if(dp[l][r] != -1) return dp[l][r];
//寻找一个定义与边[l,r]形成一个三角形
for(int k = l + 1;k < r;k++)
{
//计算这个三角形的权值
int value = (*(A + l)) * (*(A + k)) * (*(A + r));
//将当前的多边形切分成两个子多边形
int tmp = deep(A,l,k) + deep(A,k,r) + value;
//求出当前的正多边形的最小值
if( ans == -1)
{
ans = tmp;
}
else
{
ans = Min(tmp,ans);
}
}
dp[l][r] = ans;
return ans;
}
int minScoreTriangulation(int* A, int ASize)
{
N = ASize;
memset(dp,-1,sizeof(dp));
memset(flag,0,sizeof(flag));
return deep(A,0,N-1);
}
int main()
{
int n;
int a[55];
scanf("%d",&n);
for(int i = 0; i < n; i++)
{
scanf("%d",&a[i]);
}
int ans = minScoreTriangulation(a,n);
printf("%d\n",ans);
return 0;
}