• 区间DP:石子归并


    题目描述 
    Description

    有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1]。问安排怎样的合并顺序,能够使得总合并代价达到最小。

    输入描述 Input Description

    第一行一个整数n(n<=100)

    第二行n个整数w1,w2...wn  (wi <= 100)

    输出描述 Output Description

    一个整数表示最小合并代价

    样例输入 Sample Input

    4

    4 1 1 4

    样例输出 
    Sample Output
    18

    这道题可以轻松地找出状态转移方程f[i,j]:=max{f[i,k]+f[k+1,j]}+sum[i,j];

    但问题是如何递推是个问题,
    1:若正推,for i:=1 to n do
    for j:=i to n do
    这样的话,递推顺序为(1,1),(1,2),(1,3),(1,4),(2,2).....
    中间还有未求的量。
    2:若逆推,顺序为(n,n),(n-1,n-1),(n-1,n),(n-2,n-2)....。故应逆推。

    还有一点要注意,就是当前所求的区间的前趋i,后趋j,和中间变量k有(i=j-1=k)时f[i,j]:=stone[i]+stone[j];

    var num:longint;
    stone:array[1..100]of integer;
    i,j,k,l,n,max:longint;
    sum:array[1..100,1..100]of longint;
    f:array[1..100,1..100]of longint;
    
    
    begin fillchar(stone,sizeof(stone),0);
    fillchar(sum,sizeof(sum),0);
    fillchar(f,sizeof(f),$7F);
    readln(n);
    for i:=1 to n do
    read(stone[i]);
    for i:=1 to n do
    for j:=i to n do
    for k:=i to j do
    sum[i,j]:=sum[i,j]+stone[k];
    for i:=1 to n do
    f[i,i]:=0;
    for i:=n downto 1 do
    for j:=i to n do
    for k:=i to j-1 do
    if (i=k)and(k=j-1)
    then begin if f[i,j]>f[i,k]+f[k+1,j]+sum[i,j]
    then f[i,j]:=stone[i]+stone[j];
    end
    else begin if f[i,j]>f[i,k]+f[k+1,j]+sum[i,j]
    then f[i,j]:=f[i,k]+f[k+1,j]+sum[i,j];
    end;
    writeln(f[1,n]);
    end.
  • 相关阅读:
    Go 语言机制之逃逸分析
    类型转换和类型断言
    浅析rune数据类型
    Go 文件操作(创建、打开、读、写)
    字符编码笔记:ASCII,Unicode 和 UTF-8
    cmd.exe启动参数详解
    linux下.so、.ko、.a的区别
    Python 和C#的交互
    Innodb表压缩过程中遇到的坑(innodb_file_format)
    更改mysql的加密方式和密码策略
  • 原文地址:https://www.cnblogs.com/spiderKK/p/4230641.html
Copyright © 2020-2023  润新知