石子合并2
2016-10-05 06:36
204 查看
【题目描述】
在一个圆形操场的四周摆放N堆石子(N ≤ 100),现要将石子有次序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。编一程序,读入堆数N及每堆石子数(≤ 100)选择一种合并石子的方案,分别得到合并这N堆石子为一堆,可以得到的最大得分和最小得分。
【输入描述】
输入包含多个例子。第一行为N,即石子堆的数目,以下一行为N个整形,分别代表每堆石子的数目。当N=0时,输入结束。
【输出描述】
对每个例子,输出其最小得分和最大得分,这两个数值以空格间隔开,每个例子占一行。
【输入样例】
6
30 35 15 5 10 20
3
1 2 3333
6
3 4 5 6 7 8
0
【输出样例】
275 475
3339 6671
84 125
在一个圆形操场的四周摆放N堆石子(N ≤ 100),现要将石子有次序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。编一程序,读入堆数N及每堆石子数(≤ 100)选择一种合并石子的方案,分别得到合并这N堆石子为一堆,可以得到的最大得分和最小得分。
【输入描述】
输入包含多个例子。第一行为N,即石子堆的数目,以下一行为N个整形,分别代表每堆石子的数目。当N=0时,输入结束。
【输出描述】
对每个例子,输出其最小得分和最大得分,这两个数值以空格间隔开,每个例子占一行。
【输入样例】
6
30 35 15 5 10 20
3
1 2 3333
6
3 4 5 6 7 8
0
【输出样例】
275 475
3339 6671
84 125
源代码: #include<cstdio> #include<algorithm> #define INF 1000000000 using namespace std; int n,Max=0,Min=INF,i[101],f1[201][201],f2[201][201],sum[201]; //注意数据范围,f1[i][j]表示[i,j]合并的最小代价,f2[i][j]表示最大代价。 void DP() { for (int a=2;a<=n;a++) for (int b=1;b<=(n<<1)-a+1;b++) { int t=b+a-1; f1[b][t]=INF; for (int c=b;c<t;c++) { f1[b][t]=min(f1[b][t],f1[b][c]+f1[c+1][t]+sum[t]-sum[b-1]); f2[b][t]=max(f2[b][t],f2[b][c]+f2[c+1][t]+sum[t]-sum[b-1]); } } } int main() { scanf("%d",&n); for (int a=1;a<=n;a++) { scanf("%d",&i[a]); i[a+n]=i[a]; } for (int a=1;a<=(n<<1);a++) //前缀和处理。 sum[a]=sum[a-1]+i[a]; DP(); for (int a=1;a<=n;a++) { Min=min(Min,f1[a][a+n-1]); Max=max(Max,f2[a][a+n-1]); } printf("%d\n%d",Min,Max); return 0; } /* 总体思想还是和链状合并类似的。 采取“断环为链”的思想,将DP长度扩至[1,2*n],便能囊括所有情况。 */