• 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;

     

  • 相关阅读:
    使用AnsyncTask异步类从网络上下载图片
    fibonacci分治求法
    JavaScript
    JavaScript
    JavaScript
    JavaScript
    yarn安装vue后,报“文件名、目录名或卷标语法不正确。”
    VIM-Plug安装插件时,频繁更新失败,或报端口443被拒绝等
    Node.js Windows Binary二进制文件安装方法
    Linux常用命令
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/7359812.html
Copyright © 2020-2023  润新知