算法导论第四章练习题4.1-1

题目描述

  • 在你的计算机上实现最大子数组问题的暴力算法和递归算法。请指出多大的问题规模n0是性能交叉点——从此之后递归算法将击败暴力算法?

代码

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <assert.h>

using namespace std;

void generateRandomArray(int arr[], int n, int rangeL, int rangeR);//生成包含n个数的随机数组
vector<int> bruteSearch(int arr[], size_t n);//暴力搜索算法
vector<int> recursiveSearch(int arr[], int low, int high);//递归算法
vector<int> crossSubarray(int arr[], int low, int mid, int high);//用于求解递归算法中最大子字符串跨越中点的情况

int main() {
	constexpr unsigned n = 1000000;
	cout << "输入规模为:" << n << endl;
	static int arr[n];
	generateRandomArray(arr, n, -100, 100);

	clock_t start2, finish2;
	vector<int> ans2;
	start2 = clock();
	ans2 = recursiveSearch(arr, 0, n - 1);
	finish2 = clock();
	cout << "The answer of recursive search is:" << endl;
	for (auto &c : ans2) {
		cout << c << endl;
	}
	cout << "运行时间为:" << (double)(finish2 - start2) / CLOCKS_PER_SEC << endl;
	cout << "---------------------------------------" << endl;

	clock_t start1, finish1;
	vector<int> ans1;
	start1 = clock();
	ans1 = bruteSearch(arr, n);
	finish1 = clock();
	cout << "The answer of brute search is:" << endl;
	for (auto &c : ans1) {
		cout << c << endl;
	}
	cout << "运行时间为:" << (double)(finish1 - start1) / CLOCKS_PER_SEC << endl;
	cout << "---------------------------------------" << endl;
};

void generateRandomArray(int arr[], int n, int rangeL, int rangeR) {
	assert(rangeL <= rangeR);
	// srand(time(NULL)); // 随机种子
	for (int i = 0; i < n - 1; i++)
		arr[i] = rand() % (rangeR - rangeL + 1) + rangeL;
}

vector<int> bruteSearch(int arr[], size_t n) {
	int max_sum = INT_MIN;
	int left = 0;
	int right = 0;
	for (size_t i = 0; i != n - 1; ++i) {
		int sum = 0;
		for (size_t j = i; j != n; ++j) {
			sum += arr[j];
			if (sum > max_sum) {
				max_sum = sum;
				left = i;
				right = j;
			}
		}
	}
	return { left, right, max_sum};
}

vector<int> crossSubarray(int arr[], int low, int mid, int high) {
	int left_sum = INT_MIN;
	int max_left = 0;
	int max_right = 0;
	int sum = 0;
	for (int i = mid; i >= low; --i) {
		sum += arr[i];
		if (sum > left_sum) {
			left_sum = sum;
			max_left = i;
		}
	}
	int right_sum = INT_MIN;
	sum = 0;
	for (int i = mid + 1; i <= high; ++i) {
		sum += arr[i];
		if (sum > right_sum) {
			right_sum = sum;
			max_right = i;
		}
	}
	return { max_left, max_right, left_sum + right_sum };
}

vector<int> recursiveSearch(int arr[], int low, int high) {
	if (high == low) {
		return { low, high, arr[low] };
	}
	else {
		int mid = (low + high) / 2;
		vector<int> vec_left = recursiveSearch(arr, low, mid);
		vector<int> vec_right = recursiveSearch(arr, mid+1, high);
		vector<int> vec_cross = crossSubarray(arr, low, mid, high);
		if (vec_left[2] >= vec_right[2] && vec_left[2] >= vec_cross[2])
			return vec_left;
		else if (vec_right[2] >= vec_left[2] && vec_right[2] >= vec_cross[2])
			return vec_right;
		else return vec_cross;
	}
}
  • 实验发现,n<10000时,暴力搜索算法性能更好,n=10000时,两种算法性能相当,n>10000时,递归算法开始展现出明显优势
  • 实验结果如下;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是两个问题。让我分别回答。 --- 对于习题24.2-4,我们需要证明:对于有向图$G=(V,E)$,从源点$s$到任何其他点$v\in V$的最短路径上最多可以包含$|V|-1$条边。 我们可以使用反证法来证明这个结论。假设存在一条从$s$到$v$的最短路径包含了$|V|$条边。由于这是一条简单路径,所以它经过了$|V|$个顶点中的所有顶点。因此,这个路径形成了一个简单环。我们可以从这个简单环中删除任意一条边,得到一条从$s$到$v$的路径,路径长度比原来的最短路径长度更小,这与原来的最短路径的假设相矛盾。因此,假设不成立,结论得证。 --- 对于习题24.3-6,我们需要证明:如果负权重有向图$G$中不存在从源点$s$可达的负权重环,则Bellman-Ford算法能够正确地计算出从$s$到所有其他顶点的最短路径。 我们可以使用反证法来证明这个结论。假设存在一个从$s$到$v$的最短路径上存在一个负权重环。由于负权重环的存在,我们可以通过不断绕这个环走来无限制地减小路径长度,因此不存在从$s$到$v$的最短路径。但是,Bellman-Ford算法会在第$|V|$次松弛操作之前终止,并且在第$i$次松弛操作之后,算法会计算出从$s$到所有距离$s$不超过$i$的顶点的最短路径。因此,我们可以得出结论:如果负权重有向图$G$中不存在从源点$s$可达的负权重环,则Bellman-Ford算法能够正确地计算出从$s$到所有其他顶点的最短路径。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值