dp2--合并石子(一)
一、心得
二、题目
石子合并(一)
时间限制:1000 ms | 内存限制:65535 KB
难度:3
- 描述
- 有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。
- 输入
- 有多组测试数据,输入到文件结束。
每组测试数据第一行有一个整数n,表示有n堆石子。
接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开 - 输出
- 输出总代价的最小值,占单独的一行
- 样例输入
-
3 1 2 3 7 13 7 8 16 21 4 18
- 样例输出
-
9 239
- 来源
- 经典问题
三、分析
* 合并石子.cpp
* 分析:
* 状态:
* f[i][j]表示把第i堆石子到第j堆石子合并成一堆的最小代价
* sum[j]表示第1堆石子到第j堆石子的和
* 最终状态:
* f[1][n]
* 初始状态:
* f[i][i]=0;
* 状态转移方程:
* 假设最后一次合并是将(i,k)和(k+1,j)合并
* f[i][j]=min(f[i][k]+f[k+1][j]+sum[j]-sum[i-1]) (k>=i&&k<=j)
dp过程图
四、AC代码
242ms
1 /* 2 * 合并石子.cpp 3 * 分析: 4 * 状态: 5 * f[i][j]表示把第i堆石子到第j堆石子合并成一堆的最小代价 6 * sum[j]表示第1堆石子到第j堆石子的和 7 * 最终状态: 8 * f[1][n] 9 * 初始状态: 10 * f[i][i]=0; 11 * 状态转移方程: 12 * 假设最后一次合并是将(i,k)和(k+1,j)合并 13 * f[i][j]=min(f[i][k]+f[k+1][j]+sum[j]-sum[i-1]) (k>=i&&k<=j) 14 * 15 * 16 */ 17 18 #include <iostream> 19 #include <cstdio> 20 using namespace std; 21 int f[205][205]; 22 int sum[205]; 23 int a[205]; //用来存这n堆石子 24 int n; 25 26 void readData() { 27 for (int i = 1; i <= n; i++) { 28 cin >> a[i]; 29 } 30 } 31 32 void printRead() { 33 cout << "n:" << n << endl; 34 for (int i = 1; i <= n; i++) { 35 cout << a[i] << " "; 36 } 37 cout << endl; 38 } 39 40 void initArr_sum() { 41 sum[0] = 0; 42 for (int i = 1; i <= n; i++) { 43 sum[i] = a[i] + sum[i - 1]; 44 } 45 } 46 47 void printArr_sum() { 48 for (int i = 1; i <= n; i++) { 49 cout << sum[i] << " "; 50 } 51 cout << endl; 52 } 53 54 void initArr_f() { 55 //把上一轮的数据清空 56 for (int i = 0; i <= n; i++) { 57 for (int j = 0; j <= n; j++) { 58 f[i][j] = 0xfffffff; 59 } 60 } 61 //初始化 62 for (int i = 1; i <= n; i++) { 63 f[i][i] = 0; 64 } 65 } 66 67 void printArr_f() { 68 for (int i = 1; i <= n; i++) { 69 for (int j = 1; j <= n; j++) { 70 cout << f[i][j] << " "; 71 } 72 cout << endl; 73 } 74 } 75 76 void init() { 77 readData(); 78 //printRead(); 79 initArr_sum(); 80 //printArr_sum(); 81 initArr_f(); 82 //printArr_f(); 83 } 84 85 void dp() { 86 for (int i = n; i >= 1; i--) { 87 for (int j = i + 1; j <= n; j++) { 88 for (int k = i; k <= j; k++) { 89 f[i][j] = min(f[i][j], 90 f[i][k] + f[k + 1][j] + sum[j] - sum[i - 1]); 91 } 92 } 93 } 94 } 95 96 void printAns() { 97 cout << f[1][n] << endl; 98 } 99 100 int main() { 101 //freopen("src/in737.txt", "r", stdin); 102 while (scanf("%d", &n)==1) { 103 init(); 104 dp(); 105 //printArr_f(); 106 printAns(); 107 } 108 109 return 0; 110 } 111 112 /* 113 * 注意点: 114 * 1、因为求最小值,所以f要初始化为较大值 115 * f[i][j] = 0xfffffff; 116 */
五、注意点
1、因为求最小值,所以f要初始化为较大值 f[i][j] = 0xfffffff;