标签:idt algo clu article 而且 cstring lan csdn msm
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1022
题目大意:
N堆石子摆成一个环。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
例如: 1 2 3 4,有不少合并方法
解题思路:经典的石子合并问题,较原来不同的是石子是环形摆放的,而且石子数目n的范围有100增加到了1000,原本O(n^3)的算法肯定是会超时的。所以需要用四边形不等式优化将复杂度降为O(n^2),并且将数组倍增把环变为链。
于是,我们可以使用s[i][j]记录使得dp[i][j]最优的分割点(k点),并且满足s[i][j-1]<=s[i][j]<=s[i+1][j+1],那么我们的k的枚举范围就是s[i][j-1]<=s[i][j]<=s[i+1][j+1]。
复杂度证明:
代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 using namespace std; 6 const int N=2e3+5; 7 const int INF=0x3f3f3f3f; 8 9 int dp[N][N],s[N][N],sum[N],a[N];//s[i][j]为使dp[i][j]最优的分割点 10 11 int main(){ 12 int n; 13 scanf("%d",&n); 14 memset(dp,0x3f,sizeof(dp)); 15 for(int i=1;i<=n;i++){ 16 scanf("%d",&a[i]); 17 a[i+n]=a[i]; 18 } 19 for(int i=1;i<=2*n;i++){ 20 dp[i][i]=0; 21 sum[i]=sum[i-1]+a[i]; 22 s[i][i]=i; 23 } 24 for(int d=1;d<n;d++){ 25 for(int i=1;i<=2*n-d;i++){ 26 int j=i+d; 27 for(int k=s[i][j-1];k<=s[i+1][j];k++){ 28 int tmp=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]; 29 if(tmp<dp[i][j]){ 30 dp[i][j]=tmp; 31 s[i][j]=k; 32 } 33 } 34 } 35 } 36 int ans=INF,d=n-1; 37 for(int i=1;i<=2*n-d;i++){ 38 int j=i+d; 39 ans=min(ans,dp[i][j]); 40 } 41 printf("%d\n",ans); 42 return 0; 43 }
51Nod 1022 石子归并 V2(区间DP+四边形优化)
标签:idt algo clu article 而且 cstring lan csdn msm
原文地址:http://www.cnblogs.com/fu3638/p/7820464.html