UVA10003 切木棍 Cutting Sticks(区间DP、细节)

整理的算法模板合集: ACM模板


在这里插入图片描述
本题其实就是一个区间DP 的模板题,总长度为len,有n个切割点,也就是说能被切割成n+1段,所以左边界是0,有边界是n + 1,所以答案就是f[0][n + 1]
其中我们要把两个端点设为:a[0] = 0a[n + 1] = len

边界:f[i][i] = f[i][i + 1] = 0;(不然没办法转移,因为要从他们开始+)

转移方程: f [ i ] [ j ] = m i n { f [ i ] [ k ] + f [ k ] [ j ] } + a [ j ] − a [ i ] f[i][j] = min\{f[i][k]+ f[k][j]\} + a[j] - a[i] f[i][j]=min{f[i][k]+f[k][j]}+a[j]a[i]

注意根据题意,我们长度至少为2的时候(也就是有三个点)才能在中间的点将他们切开。

总时间复杂度为 O ( n 3 ) O(n^3) O(n3)

紫书上说使用四边形不等式优化可以优化到 O ( n 2 ) O(n^2) O(n2),这个有缘再学。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstring>

using namespace std;
typedef long long ll;
const int N = 507, M = 5000007, INF = 0x3f3f3f3f;
const double eps = 1e-6;

int n, m;
int f[N][N];
int len;
int a[N];

int main()
{
    while(scanf("%d", &len) != EOF && len){
        scanf("%d", &n);
        memset(f, 0x3f, sizeof f);
        for(int i = 1; i <= n; ++ i){
            scanf("%d", &a[i]);
            f[i][i] = f[i][i + 1] = 0;
        }
        //0是左端点n + 1是右端点
        a[n + 1] = len;//n个点分成n+1段
        for(int length = 2; length <= n + 1; ++ length){//从0开始0,1,2,这样才能在1点切开,0是左端点不是切割点
            for(int i = 0; i <= n - length + 1; ++ i){
                int j = i + length;
                int minv = INF;
                for(int k = i + 1; k < j; ++ k){
                    minv = min(minv, f[i][k] + f[k][j]);
                }
                f[i][j] = minv + a[j] - a[i];
            }
        }
        printf("The minimum cutting is %d.\n", f[0][n + 1]);
    }
    return 0;
}

©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页