鱼香rose'Blog

算法思想——三分

\(\Huge{算法思想——三分}\)

三分算法概念

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

适用场景

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

在区间\([l,r]\)中,令\(midl=l+\frac{r-l}{3}\),\(midr = r-\frac{r-l}{3}\),初始时分别位于\(\frac{1}{3}\)\(\frac{2}{3}\)处,然后计算这两个点的函数值,如果\(check(midl)>ckeck(midr)\),求解区间由\([l,r]\)变为\([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;
}

posted @ 2026-01-20 17:16  鱼香_rose  阅读(1)  评论(0)    收藏  举报