Cutting Sticks UVA - 10003(DP - 四边形不等式优化)

四边形不等式优化:

花费用 d[i,j] 表示 
d[i,j]=min\ \{ \ d[i,k]+d[k+1,j]\ \}+w[i,j]       (w[i,j]=sum[i,j])
四边形不等式   :  w[a,c]+w[b,d] \ \le \ w[b,c]+w[a,d] \ \ \ (a<b<c<d)  称其满足凸四边形不等式 
决策单调性       :  w[i,j]<=w[i',j']  \ \ (i' \ \le \ i \ < \ j \ \le \ j')

三个定理: 
定理一: 如果 w 同时满足四边形不等式 和 决策单调性 ,则 d 也满足四边形不等式
定理二:当定理一的条件满足时,让d[i,j]取最小值的 ks[i,j],则s[i,j-1] \le s[i,j] \le s[i+1,j]
定理三:w 为凸当且仅当 w[i,j]+w[i+1,j+1] \le w[i+1,j]+w[i,j+1]
由定理三知 判断 w 是否为凸即判断 w[i,j+1]-w[i,j]的值随着i的增加是否递减 
于是求 k 值的时候 s[i,j]只和 s[i+1,j]s[i,j-1] 有关,所以 可以以  i - j  递增为顺序递推各个状态值最终求得结果  将O(n^3)转为O(n^2)

 

题意:

题目链接:https://vjudge.net/problem/UVA-10003

给你一个长度为 len 的木棒,和 n 个切点,需要都切开,每次切花费的代价为 当前切的木棒的长度。

解题思路:

d[i,j]=min\ \{ \ d[i,k]+d[k+1,j]\ \}+w[i,j]   可以使用四边形不等式优化下。

AC代码:

未优化:

#include<bits/stdc++.h>
#define up(i, x, y) for(int i = x; i <= y; i++)
#define down(i, x, y) for(int i = x; i >= y; i--)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define IO ios::sync_with_stdio(false),cin.tie(0)
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-8;
const int mod = 1e9 + 7;
const int maxn = 100 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
using namespace std;

int a[maxn], sum[maxn];
int dp[maxn][maxn];

int main()
{
    int len; while(~scanf("%d", &len) && len)
    {
        int n; scanf("%d", &n);
        int pre = 0;
        for(int i = 1; i <= n ;i++)
        {
            int t; scanf("%d", &t);
            a[i] = t - pre;
            pre = t;
        }
        a[++n] = len - pre;
        for(int i = 1; i <= n; i++)
        {
            sum[i] = sum[i - 1] + a[i];
        }

        memset(dp, 127, sizeof(dp));
        for(int i = 1; i <= n; i++) dp[i][i] = 0;
        for(int x = 1; x <= n; x++)
        {
            for(int i = 1; i <= n - x; i++)
            {
                int j = i + x;
                for(int k = i; k < j; k++)
                {
                    dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + sum[j] - sum[i - 1]);
                }
            }
        }
        printf("The minimum cutting is %d.\n", dp[1][n]);
    }
}

四边形不等式优化:

#include<bits/stdc++.h>
#define up(i, x, y) for(int i = x; i <= y; i++)
#define down(i, x, y) for(int i = x; i >= y; i--)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define IO ios::sync_with_stdio(false),cin.tie(0)
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-8;
const int mod = 1e9 + 7;
const int maxn = 100 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
using namespace std;

int a[maxn], sum[maxn];
int dp[maxn][maxn], s[maxn][maxn];

int main()
{
    int len; while(~scanf("%d", &len) && len)
    {
        int n; scanf("%d", &n);
        int pre = 0;
        for(int i = 1; i <= n ;i++)
        {
            int t; scanf("%d", &t);
            a[i] = t - pre;
            pre = t;
        }
        a[++n] = len - pre;
        for(int i = 1; i <= n; i++)
        {
            sum[i] = sum[i - 1] + a[i];
        }

        memset(dp, 127, sizeof(dp));
        for(int i = 1; i <= n; i++) dp[i][i] = 0, s[i][i] = i;
        for(int x = 1; x <= n; x++)  // 枚举区间大小
        {
            for(int i = 1; i <= n - x; i++) //枚举区间左边界
            {
                int j = i + x;  // 求出区间有边界
                for(int k = s[i][j - 1]; k <= s[i + 1][j]; k++)
                {
                    if(dp[i][j] > dp[i][k] + dp[k + 1][j] + sum[j] - sum[i - 1])
                    {
                        dp[i][j] = dp[i][k] + dp[k + 1][j] + sum[j] - sum[i - 1];
                        s[i][j] = k;
                    }
                }
            }
        }
        printf("The minimum cutting is %d.\n", dp[1][n]);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值