トピックリンク: HDU3506モンキーパーティー
質問:円で石をマージするのと同様に、2つの石の山をマージするコストは、2つの石の山の数の合計です。すべての石をマージする最小コストを尋ねます。
分析:dp [i] [j]は区間[i、j]の最小コストを表し、p [i] [j]は区間[i、j]内の石の数を表し、四辺形の不等式最適化s [を追加します。 i] [j]は、区間[i、j]の中で最良のブレークポイントを表します。
【四辺形不等式の最適化】
a <b <= c <dの場合、f [a] [c] + f [b] [d] <= f [b] [c] + f [a] [d]の場合、fは四辺形の不等式を満たします。この時点で、最良のブレークポイントs [i] [j]は次の特性を満たします。
s [i] [j-1] <= s [i] [j] <= s [i + 1] [j]
このようにして、元の列挙間隔の開始点とブレークポイントn * nがnに最適化されます
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=2007;
int dp[maxn][maxn],s[maxn][maxn],p[maxn][maxn],a[maxn];
int n,ans;
void rua()
{
for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i+n]=a[i];
memset(dp,INF,sizeof(dp));
memset(s,0,sizeof(s));
for(int i=1;i<=n+n;i++)
{
dp[i][i]=0;
s[i][i]=i;
p[i][i]=a[i];
}
for(int i=1;i<n;i++)//区间长度
for(int j=1;i+j<2*n;j++)//区间起点
for(int k=s[j][i+j-1];k<=s[j+1][i+j];k++)
{
int tmp=p[j][k]+p[k+1][i+j];
if(dp[j][i+j]>dp[j][k]+dp[k+1][i+j]+tmp)
{
p[j][i+j]=tmp;
dp[j][i+j]=dp[j][k]+dp[k+1][i+j]+tmp;
s[j][i+j]=k;
}
}
ans=INF;
for(int i=1;i<=n+1;i++) ans=min(ans,dp[i][i+n-1]);
printf("%d\n",ans);
}
int main()
{
while(~scanf("%d",&n)) rua();
return 0;
}