四边形不等式优化

当你遇到这样的转移方程:dp[i][j] = min(dp[i][k-1], dp[k][j]) + w[i][j] 且n较大时。。。
低情商:无脑三层 for,喜提 TLE (暴力美学)
高情商:这不是有手题??? (四边形不等式优化)

虽然它俩都是三层for,但是后者的复杂度却只有O(N^2),这就是四边形不等式能干的事。

先放结论:

形如 dp[i][j] = min(dp[i][k-1], dp[k][j]) + w[i][j],其中 i <= k <= j,dp[i][j]表示区间i到j上的最值(此处以最小值为例,也可以为最大值)。
可以通过四边形不等式优化该方程,可将时间复杂度O(N ^ 3)优化至O(N ^ 2)

先抛出两个概念

1. 区间单调性

若满足 a <= b <= c <= d,且 w[b][c] <= w[a][d]。那么w具有区间单调性。
在这里插入图片描述

2. 四边形不等式

若满足 a <= b <= c <= d,且 w[a][c] + w[b][d] <= w[a][d] + w[b][c] 。那么w满足四边形不等式。

在这里插入图片描述




接着引入一个数组 s[i][j] ,表示dp[i][j] 取得最优值时对应的下标
再来两个性质:

  1. 若 w[ ][ ] 同时满足上面提到的区间单调性四边形不等式,则 dp[ ][ ] 满足四边形不等式。
  2. dp[i][j] 满足四边形不等式,则 s[i][j] 单调,即 s[i][j-1] ≤ s[i][j] ≤ s[i+1][j]

那么,现在的问题就成了求 s[ ][ ]。而根据 s[ ][ ] 的定义,应该不难求出来。


看到这里应该有想法了吧?且往下看


原本暴力的循环 ↓

for (int j = 1; j <= n; j++) 
  for (int i = j; i >= 1; i--) 
    for (int k = i; k < j; k++) 
      dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]);

四边形不等式优化 ↓

for (int j = 1; j <= n; j++) 
  for (int i = j; i >= 1; i--) 
	for (int k = s[i][j-1] ; k <= s[i+1][j] ; k++) {
	  if(dp[i][j] > dp[i][k]+dp[k+1][j]+w[i][j]) {
	    dp[i][j] = dp[i][k]+dp[k+1][j]+w[i][j];
	    s[i][j] = k;
	  }
	}

为啥这样能做到O(N^2)呢?
这是因为枚举的区间长度 len = j-i,而 s[i,j-1] 和 s[i+1,j] 的长度是 len-1,是上一次已经计算过的,可以直接调用,所以时间复杂度为 O(N^2)。

—end—

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liudashuai666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值