题目描述
给定一个数组arr,长度为n。代表排有分数的气球。 每打爆一个气球都能获得分数,假设打爆气球的分数为X,获得分数的规则如下:
1)如果被打爆气球的左边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为L:如果被打爆气球的右边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为R.获得分数为LXR
2)如果被打爆的气球的左边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为L:如果被打爆气球的右边所有气球都已经被打爆,获得分数为LX。
3)如果被打爆气球的左边所有的气球都已经被打爆:如果被打爆气球的右边有没被打爆的气球,找到离被打爆气球最近的气球。获得分数为XR.
4)如果被打爆气球的左边和右边所有的气球都已经被打爆。获得分数为X。
目标是打爆所有气球,获得每次打爆的分数。通过选择打爆气球的顺序,可以得到不同的总分,请返回能获得的最大分数。
输入描述:
输出包括两行,第一行包括一个整数n(0<=n<=500),第二行包括n个整数,代表数组arr (1<=arr[i]<=100)。
输出描述:
输出包括一个整数,代表可能获得的最大分数。
示例1
输入
复制
3
3 2 5
输出
复制
50
说明
2->1->3 325+3*5+5=50
示例2
输入
复制
8
23 4 45 65 23 43 54 56
输出
复制
639019
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long ll;
int arr[507];
ll dp[507][507];//从i到j的最大分数
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&arr[i]);
arr[0]=1 , arr[n+1]=1;
for(int i=1;i<n;i++)
dp[i][i]= arr[i]*arr[i-1]*arr[i+1];
if(n==1)//特判
{
cout<<arr[n]<<endl;
return 0;
}
for(int i=n;i>0;i--)
{
for(int j=i+1;j<=n;j++)
{
//最后打左边
dp[i][j]= dp[i+1][j] + arr[i]*arr[i-1]*arr[j+1];
//打右边或左边
dp[i][j]= max( dp[i][j] , dp[i][j-1] +arr[j]*arr[i-1]*arr[j+1] ) ;
for(int z=i+1;z<j;z++)
{
dp[i][j]= max( dp[i][j] , dp[i][z-1] + dp[z+1][j] + arr[z]*arr[i-1]*arr[j+1] );
}
}
}
// for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=n;j++)
// cout<<dp[i][j]<<" ";
// cout<<endl;
// }
cout<<dp[1][n]<<endl;
return 0;
}
代码优化
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long ll;
int arr[507];
ll dp[507][507];//从i到j的最大分数
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&arr[i]);
arr[0]=1 , arr[n+1]=1;
for(int i=1;i<n;i++)
dp[i][i]= arr[i]*arr[i-1]*arr[i+1];
if(n==1)//特判
{
cout<<arr[n]<<endl;
return 0;
}
for(int i=n;i>0;i--)
{
for(int j=i+1;j<=n;j++)
{
for(int z=i;z<=j;z++)
{
dp[i][j]= max( dp[i][j] , dp[i][z-1] + dp[z+1][j] + arr[z]*arr[i-1]*arr[j+1] );//当 z-1<i 或 z+1>j 是dp默认为0,可以减少代码量
}
}
}
cout<<dp[1][n]<<endl;
return 0;
}