201612-4 压缩编码
题目
思路
看了半天明白了是果子合并问题加上只能相邻合并的限制条件。奈何不会dp,只能贪心混分。混分代码就不放了。
然后我学习了一下大佬们的dp。有个类似的经典问题,石子合并问题。其状态转移方程:
正常递推不优化的话也可以AC,大概2.7s。用四边形不等式优化一下就60+ms了。
AC代码如下
#include<cstdio>
#include<algorithm>
using namespace std;
const int inf=1e8;
int n,dp[1001][1001],sum[1001][1001],t[1001];
int kmin[1001][1001];//记录使dp[i][j]最小的k
int main(){
scanf("%d",&n);
fill(dp[0],dp[0]+1001*1001,inf);
for(int i=0;i<n;i++){
scanf("%d",&t[i]);
dp[i][i]=0;
sum[i][i]=t[i];
kmin[i][i]=i;
}
for(int len=2;len<=n;len++){
for(int i=0;i<n&&i+len-1<n;i++){
int j=i+len-1;
for(int k=kmin[i][j-1];k<=kmin[i+1][j];k++){
sum[i][j]=sum[i][k]+sum[k+1][j];
if(dp[i][k]+dp[k+1][j]+sum[i][j]<dp[i][j]){
dp[i][j]=dp[i][k]+dp[k+1][j]+sum[i][j];
kmin[i][j]=k;
}
}
/*优化前的代码
for(int k=i;k<=j;k++){
sum[i][j]=sum[i][k]+sum[k+1][j];
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[i][j]);
}
*/
}
}
printf("%d\n",dp[0][n-1]);
return 0;
}