微信扫一扫打赏支持

dp2--合并石子(一)

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;

 

 

 

posted @ 2017-08-14 19:34  范仁义  阅读(274)  评论(0编辑  收藏  举报