Description
做如下两个模型的石子合并,如下模型石子都不能移动出列,且合并都仅发生在相邻两堆石子中: (1)第一个模型:一行排列且相邻合并 有n堆石子A1,A2,...,An形成一行,每堆石头个数记为ai(1<=i<=n),相邻两堆可合并,合并的分值为新堆的 石子数。求合并为一堆的最低得分和最高得分。 (2)第二个模型:一圈排列且相邻合并 有n堆石子A1,A2,...,An形成首位相连的一个环形,An和A1相邻,每堆石头个数记为ai(1<=i<=n),相邻两堆 可合并,合并的分值为新堆的石子数。求合并为一堆的最低得分和最高得分。 例如4堆石子,每堆石子个数:9 4 4 5 若排成一行,最小分值:(4+4)+(8+5)+(9+13)=43,最大分值:(9+4)+(13+4)+(17+5)=52。若排成圈状,最小分值:(4+4)+(8+5)+(9+13)=43,最大分值:(9+5)+(14+4)+(18+4)=54。
输入:
4
9 4 4 5
输出:
43 53
43 54
思路:
这是一道动态规划问题,与矩阵连乘的最小数乘次数类似,因此求法也类似。
针对第一种模型,设m[i][j]记录i到j的最小得分情况,将i到j划分成任意的两份,则
当 i=j时, m[i][j] = 0;
当 i<j时, m[i][j] = min{ m[i,k]+m[k+1,j] | for all k, i<=k<j } + sum{ a(t) | for all t, i<=t<=j };
最终m[1][n]的结果即为所求。
同理,可推出最大得分情况
第二种模型,可以化成第一种模型,即A1,A2,...,An的环形,可以看成 A1 ... An A1 ... An-1,共 2n-1 堆的第一种模型。但是我们求的长度还是n。所以
我们所求即为 m[1,n], m[2,n+1], …, m[n,2n-1]这n个斜行元素中的最小值,
min{ m[i, n+i-1] | for all i, 1<=i<=n }以下为代码:#include <iostream> #define N 101 #define X 200 using namespace std; void min1(int a[N], int n, int m[N][N]){ for(int i=1; i<=n; i++) m[i][i] = 0;//链长为1 for(int r=2; r<=n; r++){//链长 >= 2 for(int i=1; i<=n-r+1; i++){// i的取值 int j = i+r-1;// j的取值 int sum = 0; for(int p=i-1; p<j; p++){ sum += a[p]; } //求最小的m[i][j] m[i][j] = m[i+1][j] + sum; for(int k=i+1; k<j; k++){// k的取值 int t = m[i][k] + m[k+1][j] + sum; if(t < m[i][j]) m[i][j] = t; } } } } void min2(int a[X], int n, int c[X][X]){ for(int i=1; i<=n; i++) c[i][i] = 0; for(int r=2; r<=n; r++){ for(int i=1; i<=n-r+1; i++){ int j = i+r-1; int sum = 0; for(int p=i-1; p<j; p++){ sum += a[p]; } c[i][j] = c[i+1][j] + sum; for(int k=i+1; k<j; k++){ int t = c[i][k] + c[k+1][j] + sum; if(t < c[i][j]) c[i][j] = t; } } } } void max1(int a[N], int n, int m[N][N]){ for(int i=1; i<=n; i++) m[i][i] = 0; for(int r=2; r<=n; r++){ for(int i=1; i<=n-r+1; i++){ int j = i+r-1; int sum = 0; for(int p=i-1; p<j; p++){ sum += a[p]; } m[i][j] = m[i+1][j] + sum; for(int k=i+1; k<j; k++){ int t = m[i][k] + m[k+1][j] + sum; if(t > m[i][j]) m[i][j] = t; } } } } void max2(int a[X], int n, int c[X][X]){ for(int i=1; i<=n; i++) c[i][i] = 0; for(int r=2; r<=n; r++){ for(int i=1; i<=n-r+1; i++){ int j = i+r-1; int sum = 0; for(int p=i-1; p<j; p++){ sum += a[p]; } c[i][j] = c[i+1][j] + sum; for(int k=i+1; k<j; k++){ int t = c[i][k] + c[k+1][j] + sum; if(t > c[i][j]) c[i][j] = t; } } } } int main() { int n; int a[N]; int b[X]; int m[N][N]; int c[X][X]; cin >> n; for(int i=0; i<n; i++){ cin >> a[i]; } for(int i=0; i<2*n-1; i++){ b[i] = a[i%n]; } min1(a,n,m); cout << m[1][n] << " "; max1(a,n,m); cout << m[1][n] << endl;; min2(b,2*n-1,c); int temp; temp = c[1][n]; for(int j=2; j<=n; j++){ if(temp > c[j][n+j-1]) temp = c[j][n+j-1]; } cout << temp << " "; max2(b,2*n-1,c); temp = c[1][n]; for(int j=2; j<=n; j++){ if(temp < c[j][n+j-1]) temp = c[j][n+j-1]; } cout << temp << endl; return 0; }