3 1 2 3 7 13 7 8 16 21 4 18
9 239
题目在:
Here
这是一道经典的区间DP,做出来也花了不少时间,具体注释见代码。这里要注意的是sum数组是一个前缀和数组,需要注意的一点就是sum[i]=a[0]+a[1]+...+a[i];
sum[j]=a[0]+a[1]+a[2]+...+a[j],那么显然sum[i~j]=sum[j]-sum[i]+a[i],即sum[i~j]=sum[j]-sum[i-1].不然会减去a[i]。。
还有就是记忆化搜索这块儿,题目说最终合并为一堆,那么当本来只有一堆的时候合并代价是0,我写成了num[i]。注意这几点便可以把这道问题解决了。
/****************************************************
* author:crazy_石头
* Pro:石子合并问题
* algorithm:区间DP
* Time:420ms
* Judge Status:Accepted
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define rep(i,h,n) for(int i=(h);i<=(n);i++)
#define ms(a,b) memset((a),(b),sizeof(a))
#define eps 1e-6
#define INF 1<<29
#define LL __int64
const int maxn=200+5;
const int maxm=1000000+10;
int dp[maxn][maxn];
int sum[maxn],num[maxn];
inline int dfs(int i,int j)
{
if(dp[i][j]!=INF)return dp[i][j];
if(i==j)return dp[i][j]=0;//题目要合并为一堆,如果本身是一堆,那么不用合并,即代价为0;
if(i+1==j)return dp[i][j]=num[i]+num[j];//两堆的话,合并代价等于这两堆的数量相加;
if(i>j)return dp[i][j]=0;
//其余情况,将大范围划小,则i~j间花费的费用等于i~k的代价加上k+1到j的代价并加上i~j间石子数目;
for(int k=i;k>n)
{
int m;
ms(sum,0);
cin>>num[0];
sum[0]=num[0];
for(int i=1;i>num[i];
sum[i]=sum[i-1]+num[i];
}
for(int i=0;i