算法思想——三分

三分算法概念

相信大家都对二分思想比较熟悉了,但是三分思想却不一定非常熟悉,因为在日常刷题过程中二分用的比较多一些,比如二分答案或是二分查找。我们都知道,二分思想在使用的过程中是有条件限制的,要求我们数据必须是线性的、单调的。而三分思想和二分的思想几乎一致,但是限制不同,所以解决的问题也不同。
二分可以解决单调问题,也可抽象为一次函数问题;三分可以解决单峰问题,可抽象为二次函数问题。

适用场景

三分算法适用于求解凸性函数的极值问题,二次函数就是一个典型的单峰函数。 二分利用的是函数的单调性,三分算法利用的是函数的单峰性。
如图所示:
在这里插入图片描述

在区间 [ l , r ] [l,r] [l,r]中,令 m i d l = l + r − l 3 midl=l+\frac{r-l}{3} midl=l+3rl, m i d r = r − r − l 3 midr = r-\frac{r-l}{3} midr=r3rl,初始时分别位于 1 3 \frac{1}{3} 31 2 3 \frac{2}{3} 32处,然后计算这两个点的函数值,如果 c h e c k ( m i d l ) > c k e c k ( m i d r ) check(midl)>ckeck(midr) check(midl)>ckeck(midr),求解区间由 [ l , r ] [l,r] [l,r]变为 [ l , m i d r ] [l,midr] [l,midr]需要注意的是,三分法严格单调,在出现函数值相等的时候该方法将不适用。

模板(三分答案)

//check函数根据题目要求写
while(l <= r) {
	int midl = l + (r - l) / 3;
	int midr = r - (r - l) / 3;
	if(check(midl) <= check(midr)) r = midr - 1;
	else l = midl + 1;
}
res = min(check(r), check(l));

例题

AcWing 5201. 午餐音乐会

AC代码

主要思路已在代码中注释

#include<bits/stdc++.h>

using namespace std;

#define IOS ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
#define ll long long 
#define ull unsigned long long 
#define PII pair<int, int>
#define lowbit(x) (x & -x)
// #define mid ((l + r) >> 1)
#define ALL(x) (x.begin(), x.end())
#define endl '\n'
#define fi first 
#define se second

const int INF = 0x7fffffff;
const int mod = 1e9 + 10;
const int N = 2e5 + 10;

int n;
struct {int p, w, d;} a[N];

ll check(int mid) {
	ll res = 0;
	for(int i = 1; i <= n; i ++ ) {
		int p = a[i].p, w = a[i].w, d = a[i].d;
		//在区域内不需要移动
		if(mid >= p - d && mid <= p + d) continue;
		//计算移动成本
		if(mid < p) res += (ll)(p - d - mid) * w;
		else res += (ll)(mid - p - d) * w;
	}
	return res;
}

signed main(void) {
	IOS

	cin >> n;
	for(int i = 1; i <= n; i ++ ) {
		int p, w, d; cin >> p >> w >> d;
		a[i] = {p, w, d};
	}
	//三分模板
	int l = 0, r = 1e9;
	while(l <= r) {
		int midl = l + (r - l) / 3;
		int midr = r - (r - l) / 3;
		if(check(midl) <= check(midr)) r = midr - 1;
		else l = midl + 1;
	}
	
	cout << min(check(r), check(l)) << endl;

	return 0;
}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值