四边形不等式优化:
花费用 表示
四边形不等式 : 称其满足凸四边形不等式
决策单调性 :
三个定理:
定理一: 如果 同时满足四边形不等式 和 决策单调性 ,则 也满足四边形不等式
定理二:当定理一的条件满足时,让取最小值的 为,则
定理三: 为凸当且仅当
由定理三知 判断 是否为凸即判断 的值随着i的增加是否递减
于是求 值的时候 只和 和 有关,所以 可以以 i - j 递增为顺序递推各个状态值最终求得结果 将转为
题意:
题目链接:https://vjudge.net/problem/UVA-10003
给你一个长度为 len 的木棒,和 n 个切点,需要都切开,每次切花费的代价为 当前切的木棒的长度。
解题思路:
可以使用四边形不等式优化下。
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]);
}
}