Luogu【P1880】石子合并(环形DP)
先放上luogu的石子合并题目链接
这是一道环形DP题,思想和能量项链很像,在预处理过程中的手法跟乘积最大相像。
用一个m[][]数组来存储石子数量,m[i][j]表示从第 i 堆石子到第 j 堆石子的总数。
接下来三重循环
i 表示合并操作的起始位置, j 表示合并操作的终点,也就是把 i 到 j 合并
k表示间断点,即 i 到 j 合并过程中选择k点来作为合并位置
状态转移方程
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+m[i][k]+m[k+1][j]);
d[i][j]=min(d[i][j],d[i][k]+d[k+1][j]+m[i][k]+m[k+1][j]);
注意该题有一个拆环为链的思想,设从1到n的石子数为12345
实际存到数组里的就是123451234
这样化成链就可以避免复杂的取余 毕竟作者循环队列学的不好,用一个环做的话一会就搞晕了
最后贴代码
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 int q[1000]; 5 int m[300][300]; 6 int f[300][300]; 7 int d[300][300]; 8 int main(){ 9 //memset(d,127/3,sizeof(d)); 10 int n; 11 cin>>n; 12 for(int i=1;i<=n;++i){ 13 cin>>q[i]; 14 q[i+n]=q[i]; 15 } 16 m[1][1]=q[1]; 17 for(int i=1;i<=n*2-1;++i) m[1][i]=m[1][i-1]+q[i]; 18 for(int i=1;i<=n*2-1;++i) 19 for(int j=i;j<=n*2-1;++j) 20 m[i][j]=m[1][j]-m[1][i-1]; 21 for(int i=n*2-1;i>=1;--i) 22 for(int j=i+1;j<=i+n&&j<n*2;++j){ 23 d[i][j]=0x7fffffff; 24 for(int k=i;k<j;++k){ 25 f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+m[i][k]+m[k+1][j]); 26 d[i][j]=min(d[i][j],d[i][k]+d[k+1][j]+m[i][k]+m[k+1][j]); 27 } 28 } 29 int maxx=0,minn=0x7fffffff; 30 for(int i=1;i<=n;++i){ 31 minn=min(minn,d[i][i+n-1]); 32 maxx=max(maxx,f[i][i+n-1]); 33 } 34 cout<<minn<<endl<<maxx; 35 return 0; 36 }