您的位置:首页 > 其它

洛谷Oj-能量项链-区间DP

2017-09-25 09:32 162 查看
问题描述:

在Mars星球上,每个Mars人都随身佩带着一串能量项链。在项链上有N颗能量珠。能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。因为只有这样,通过吸盘(吸盘是Mars人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量。如果前一颗能量珠的头标记为m,尾标记为r,后一颗能量珠的头标记为r,尾标记为n,则聚合后释放的能量为m*r*n(Mars单位),新产生的珠子的头标记为m,尾标记为n。

需要时,Mars人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。

例如:设N=4,4颗珠子的头标记与尾标记依次为(2,3) (3,5) (5,10) (10,2)。我们用记号⊕表示两颗珠子的聚合操作,(j⊕k)表示第j,k两颗珠子聚合后所释放的能量。则第4、1两颗珠子聚合后释放的能量为:

(4⊕1)=10*2*3=60。

这一串项链可以得到最优值的一个聚合顺序所释放的总能量为

((4⊕1)⊕2)⊕3)=10*2*3+10*3*5+10*5*10=710。

AC代码(递推):

int a[300],dp[300][300];
int main()
{
int n;
//输入
cin >> n;
for(int i = 1; i <= n; ++i)
{
int t;
scanf("%d",&t);
a[i] = a[n + i] = t;//将环拆成链
}
for(int i = 1; i <= n; ++i)//初始化,自己无法与自己合并,因此释放的能量为0(起思路清晰作用,实际上dp[i][i]的值本来就是0)
dp[i][i] = 0;
for(int l = 2; l <= n; ++l)//枚举区间长度
for(int i = 1; l + i - 1 <= 2 *n - 1; ++i)//枚举区间起点。注意i <= n错!!!
{
int j = l + i - 1;//计算区间终点
for(int k = i; k <= j - 1; ++k)//枚举区间内的点,作为分隔点
//计算释放出的能量是关键
dp[i][j] = max(dp[i][j],dp[i][k] + dp[k + 1][j] + a[i] * a[k + 1] * a[j + 1]);
}
int ans = -inf;
for(int i = 1; i <= n; ++i)//找出最大值
ans = max(ans,dp[i][n + i - 1]);
cout << ans << endl;
return 0;
}


AC代码(记忆化搜索):

int a[210],dp[210][210];
int dfs(int i,int j)
{
if(dp[i][j])//直接返回
return dp[i][j];
if(i == j)//边界条件,自己无法和自己合并,因此释放的能量为0
return 0;
for(int k = i; k <= j - 1; ++k)//以k为分隔点
dp[i][j] = max(dp[i][j],dfs(i,k) + dfs(k + 1,j) + a[i] * a[k + 1] * a[j + 1]);//记忆化
return dp[i][j];
}
int main()
{
int n;
//输入
cin >> n;
for(int i = 1; i <= n; ++i)
{
int t;
scanf("%d",&t);
a[i] = a[n + i] = t;//将环拆成链
}
int ans = -inf;
for(int i = 1; i <= n; ++i)
ans = max(ans,dfs(i,i + n - 1));//保证区间[i,i + n - 1]的长度为n
cout << ans << endl;
return 0;
}


解决方法:

这道题是区间DP,乍一看会觉得和石子合并的问题很相似。

DP的模板好套,就是需要注意的细节很多。

比较难写的就是合并珠子释放能量的语句
a[i] * a[k + 1] * a[j + 1]




画图可得,两个大珠子是由区间内若干个小珠子合并而成的,又联系a[i]的意义,所以得出如上的公式

大区间的最优解由小区间的最优解得来,基于分治的思想,我们不断划分区间,直到区间内只有一个元素,枚举它们的组合,求得所有情况合并后的最优值。

通过小区间更新大区间,最终获得指定区间的最优值

dp[i][j]的含义是区间[i,j]内元素合并所获得的最大收益

区间DP大体框架如上代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: