首页 > 编程语言 >「学习笔记」Garsia-Wachs 算法

「学习笔记」Garsia-Wachs 算法

时间:2023-06-14 21:44:53浏览次数:40  
标签:Garsia ch int ll 算法 Wachs

前言
本文的资料和图片均来自 \(\texttt{OI-Wiki}\)。

引入

题目描述
在一个操场上摆放着一排 \(N\) 堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的 \(2\) 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。
试设计一个算法,计算出将 \(N\) 堆石子合并成一堆的最小得分。
\((N \leq 40000)\)

过程

我们看到这个题,自然而然会想到区间 DP,即朴素的做法。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll r[600], g[600];
ll dp[600][600];

int main() {
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) {
		scanf("%lld", &r[i]);
		r[i + n] = r[i];
		g[i] = g[i - 1] + r[i];
		dp[i][i] = 0;
	}
	for (int i = n + 1; i <= 2 * n; ++ i) {
		dp[i][i] = 0;
		g[i] = g[i - 1] + r[i];
	}
	for (int l = 1; l < n; ++ l) {
		for (int i = 1, j = i + l; i < n * 2 && j <= n * 2; ++ i, j = i + l) {
			dp[i][j] = 100000000;
			for (int k = i; k < j; ++ k) {
				dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + g[j] - g[i - 1]);
			}
		}
	}
	ll minn = 0x3f3f3f3f;
	for (int i = 1; i <= n; ++ i) {
		minn = min(minn, dp[i][i + n - 1]);
	}
	printf("%lld", minn);
	return 0;
}

交上去后,你会发现,RE 了 \(7\) 个。
为什么?
因为 \(n\) 太大了,二维数组开不下,其次就算是用了什么不为人知的手段开下了这么大的数组,\(n^2\) 的复杂度也铁定超时。
这可怎么办呢?
下面介绍一种专门处理石子合并这类问题的算法——Garsia-Wachs 算法

Garsia-Wachs 算法

Garsia-Wachs 的步骤如下:
在序列的两端设置极大值。
在序列中找到前三个连续的权重值 \(x, y, z\) 使得 \(x \leq z\)。因为序列结尾的最大值大于之前的任意两个有限值,所以总是存在这样的三元组。
从序列中移除 \(x\) 和 \(y\),并在原来 \(x\) 的位置以前大于或等于 \(x+y\) 且距 \(x\) 最近的值的右边重新插入元素,元素值为 \(x+y\)。因为左端最大值的存在,所以总是存在这样的位置。
为了有效地实现这一阶段,该算法可以在任何平衡二叉查找树结构中维护当前值序列。这样的结构允许我们在对数时间内移除 \(x\) 和 \(y\),并重新插入新节点 \(x + y\)。
在每一步中,数组中位于偶数索引上直到 \(y\) 值的权重形成了一个递减序列,位于奇数索引位的权重形成另一个递减序列。因此,重新插入 \(x+y\) 的位置可以通过在对数时间内对这两个递减序列使用平衡树执行两次二分查找找到。通过从前一个三元组 \(z\) 值开始的线性顺序搜索,我们可以在总线性时间复杂度内执行对满足 \(x \leq z\) 的第一个位置的搜索。
如果实在不会平衡树,vectorinserterase 操作也是个不错的选择呢!
Garsia-Wachs 算法的总时间复杂度为 \(O(n\log n)\),时间复杂度证明?我只能说,学 OI 记住结论就好了,证明,那是数学要考虑的事,不是 OI 要考虑的事 考试又不会让你证明时间复杂度
至于正确性的证明我也不会= =,这个算法应用范围十分有限,因此学的价值不是很高,“会用” + “知道有这个东西” 就行了
关于上面那道引入题的代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

inline ll read() {
	ll x = 0;
	int fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

const int N = 4e4 + 5;

int n, ans;
vector<int> g;

int merge() {
	int k = g.size() - 2;
	for (int i = 0; i <= k; ++ i) {
		if (g[i] <= g[i + 2]) {
			k = i;
			break;
		}
	}
	int tmp = g[k] + g[k + 1];
	g.erase(g.begin() + k);
	g.erase(g.begin() + k);
	int t = -1;
	for (int i = k - 1; i >= 0; -- i) {
		if (g[i] >= tmp) {
			t = i;
			break;
		}
	}
	g.insert(g.begin() + t + 1, tmp);
	return tmp;
}

int main() {
	n = read();
	for (int i = 1; i <= n; ++ i) {
		g.emplace_back(read());
	}
	for (int i = 1; i < n; ++ i) {
		ans += merge();
	}
	printf("%d\n", ans);
	return 0;
}

标签:Garsia,ch,int,ll,算法,Wachs
From: https://www.cnblogs.com/yifan0305/p/17481364.html

相关文章

  • 文心一言 VS 讯飞星火 VS chatgpt (41)-- 算法导论5.4 5题
    五、在大小为n的集合中,一个k字符串构成一个k排列的概率是多少?这个问题和生日悖论有什么关系?文心一言:在大小为n的集合中,一个k字符串构成一个k排列的概率是1/k!,这是由于排列的总数是k!,而每个字符串被选中的概率是相等的,因此每个字符串构成一个排列的概率是1/k!。这个问题和生日......
  • 文心一言 VS 讯飞星火 VS chatgpt (41)-- 算法导论5.4 5题
    五、在大小为n的集合中,一个k字符串构成一个k排列的概率是多少?这个问题和生日悖论有什么关系?文心一言:在大小为n的集合中,一个k字符串构成一个k排列的概率是1/k!,这是由于排列的总数是k!,而每个字符串被选中的概率是相等的,因此每个字符串构成一个排列的概率是1/k!。这个问题和生日悖论......
  • 简单易学的机器学习算法——集成方法(Ensemble Method)
    一、集成学习方法的思想    前面介绍了一系列的算法,每个算法有不同的适用范围,例如有处理线性可分问题的,有处理线性不可分问题。在现实世界的生活中,常常会因为“集体智慧”使得问题被很容易解决,那么问题来了,在机器学习问题中,对于一个复杂的任务来说,能否将很多的机器学习算法......
  • 智能算法——PageRank
    一、PageRank的基本概念1、PageRank的概念  PageRank,即网页排名算法,又称为网页级别算法,是由佩奇和布林在1997年提出来的链接分析算法。PageRank是用来标识网页的等级、重要性的一种方法,是衡量一个网页的重要指标。PageRank算法在谷歌的搜索引擎中对网页质量的评价起到了重要的......
  • 简单易学的机器学习算法——K-近邻算法
    一、近邻算法(NearestNeighbors)1、近邻算法的概念近邻算法(NearestNeighbors)是一种典型的非参模型,与生成方法(generalizingmethod)不同的是,在近邻算法中,通过以实例的形式存储所有的训练样本,假设有m个训练样本:此时需要存储这m个训练样本,因此,近邻算法也称为基于实例的模型......
  • 简单易学的机器学习算法——朴素贝叶斯
    一、贝叶斯定理  1、条件概率B发生的情况下,事件A发生的概率,用表示。  2、全概率公式     含义是:如果和构成样本空间的一个划分,那么事件B的概率,就等于和的概率分别乘以B对这两个事件的条件概率之和。  3、贝叶斯推断        其中称为先验概率,即......
  • 简单易学的机器学习算法——极限学习机(ELM)
    一、极限学习机的概念    极限学习机(ExtremeLearningMachine)ELM,是由黄广斌提出来的求解单隐层神经网络的算法。    ELM最大的特点是对于传统的神经网络,尤其是单隐层前馈神经网络(SLFNs),在保证学习精度的前提下比传统的学习算法速度更快。二、极限学习机的原理EL......
  • 简单易学的机器学习算法——Logistic回归
    一、Logistic回归的概述  Logistic回归是一种简单的分类算法,提到“回归”,很多人可能觉得与分类没什么关系,Logistic回归通过对数据分类边界的拟合来实现分类。而“回归”也就意味着最佳拟合。要进行最佳拟合,则需要寻找到最佳的拟合参数,一些最优化方法就可以用于最佳回归系数的确......
  • 优化算法——遗传算法
    与遗传算法的第一次接触遗传算法是我进入研究生阶段接触的第一个智能算法,从刚开始接触,到后来具体去研究,再到后来利用遗传算法完成了水利水电的程序设计比赛,整个过程中对遗传算法有了更深刻的理解,在此基础上,便去学习和研究了粒子群算法,人工蜂群算法等等的群体智能算法。想利用这个时......
  • 简单易学的机器学习算法——因子分解机(Factorization Machine)
    一、因子分解机FM的模型    因子分解机(FactorizationMachine,FM)是由SteffenRendle提出的一种基于矩阵分解的机器学习算法。1、因子分解机FM的优势    对于因子分解机FM来说,最大的特点是对于稀疏的数据具有很好的学习能力。现实中稀疏的数据很多,例......