C++ 采用分治技术的最小子向量大小k
早上好,我有问题要解决: 你有一个大小为n的向量,你想找到一个大小为m的子向量,并且它的元素之和最小 这一工作原理的一个例子是: 其中最小子向量为:{1,3,1},和为5 我需要通过暴力(下面解释的滑动窗口)和分而治之的技术来分析这个问题。然后,我将写一份比较报告,并解释滑动窗口的效果要好得多。本文是针对一个大学项目的算法比较。但我需要用D&C明确地构建它 我已经按如下方式做了,但是我在基本情况和返回最小和子向量方面有问题C++ 采用分治技术的最小子向量大小k,c++,algorithm,recursion,divide-and-conquer,C++,Algorithm,Recursion,Divide And Conquer,早上好,我有问题要解决: 你有一个大小为n的向量,你想找到一个大小为m的子向量,并且它的元素之和最小 这一工作原理的一个例子是: 其中最小子向量为:{1,3,1},和为5 我需要通过暴力(下面解释的滑动窗口)和分而治之的技术来分析这个问题。然后,我将写一份比较报告,并解释滑动窗口的效果要好得多。本文是针对一个大学项目的算法比较。但我需要用D&C明确地构建它 我已经按如下方式做了,但是我在基本情况和返回最小和子向量方面有问题 // Function to find the minimum bet
// Function to find the minimum between two numbers
int min(int a, int b) { return (a < b)? a : b; }
// Function to find the minimum between three numbers
int min(int a, int b, int c) { return min(min(a, b), c); }
// Function to find the minimum sum that passes through the center of the vector
int minSumCenter(int v[], int l, int center, int h)
{
// Elements to the left of the center
int sum = 0;
int left_sum = INT_MAX;
for (int i = center; i >= l; i--)
{
sum = sum + v[i];
if (sum < left_sum)
left_sum = sum;
}
// Elements to the right of centre
sum = 0;
int right_sum = INT_MAX;
for (int i = center+1; i <= h; i++)
{
sum = sum + v[i];
if (sum < right_sum)
right_sum = sum;
}
// Return de los elementos que están tanto a la izquierda como a la derecha
return left_sum + right_sum;
}
// Minimum sum sub-vector size m, size v is h-l
int subvectorMinDyV(int v[], int l, int h, int m){
// Base Case 1
if ((h-l) <= m) {
int sum = 0;
for(int i=0; i<m; i++)
sum += v[i];
return sum;
// Base Case 2
}else if(m*2-1 <= (h-l)){
int sum=0;
int sumMin = INT_MAX;
for(int i=0; i<(l+h)-m;i++){
sum=0;
for(int j=i; j<m; j++)
sum += v[j];
if(sum < sumMin)
sumMin = sum;
}
return sumMin;
}
int center = (l + h)/2;
/* Possible cases
a) minimum sum sub-vector is on the left
b) minimum sum sub-vector is on the right
c) minimum sum sub-vector is a in the middle */
return min(subvectorMinDyV(v, l, center, m),
subvectorMinDyV(v, center+1, h, m),
minSumCenter(v, l, center, h));
}
int main(){
int v[] = {6,10,4,2,14,1};
int n = sizeof(v)/sizeof(v[0]);
int sumMin = subvectorMinDyV(v, 0, n-1, 3);
cout << "The minimum amount with DyV is: " << sumMin << endl;
return 0;
}
//函数查找两个数字之间的最小值
intmin(inta,intb){返回(a=l;i--)
{
总和=总和+v[i];
如果(总和<左总和)
左和=和;
}
//中间偏右的元素
总和=0;
int right_sum=int_MAX;
对于(inti=center+1;i如果你观察你的例子,那么你会发现数组是如何分区的
for n = 6, m = 3
v = 6|10|4|2|14|1
---------------
p = 0|1 |2|3|4 |5
g1: 0 1 2
g2: 1 2 3 (1 2 sum already calculated)
g3: 2 3 4 (2 3 sum already calculated)
g4: 3 4 5 (3 4 sum already calculated)
当你在收集m元素后从左向右移动时,你需要减去c-mth位置元素。其中
c`是当前位置
void subvectorMin(int* v, int n, int m, int p, int sum){
if (p >= n) {
return sum;
}
int tmp = sum - v[p-m]+ v[p];
return Min(sum, Min(tmp, subvector(v, n, m, p+1, tmp)));
}
main() {
for (i = 0; i < m; i++)
sum += v[i];
subvectorMin(v, n, m, m,sum);
void subvectorMin(int*v,int n,int m,int p,int sum){
如果(p>=n){
回报金额;
}
int tmp=总和-v[p-m]+v[p];
返回Min(和,Min(tmp,子向量(v,n,m,p+1,tmp));
}
main(){
对于(i=0;i
如果你观察你的例子,你会发现数组是如何分区的
for n = 6, m = 3
v = 6|10|4|2|14|1
---------------
p = 0|1 |2|3|4 |5
g1: 0 1 2
g2: 1 2 3 (1 2 sum already calculated)
g3: 2 3 4 (2 3 sum already calculated)
g4: 3 4 5 (3 4 sum already calculated)
当你在收集m元素后从左向右移动时,你需要减去c-mth位置元素。其中
c`是当前位置
void subvectorMin(int* v, int n, int m, int p, int sum){
if (p >= n) {
return sum;
}
int tmp = sum - v[p-m]+ v[p];
return Min(sum, Min(tmp, subvector(v, n, m, p+1, tmp)));
}
main() {
for (i = 0; i < m; i++)
sum += v[i];
subvectorMin(v, n, m, m,sum);
void subvectorMin(int*v,int n,int m,int p,int sum){
如果(p>=n){
回报金额;
}
int tmp=总和-v[p-m]+v[p];
返回Min(和,Min(tmp,子向量(v,n,m,p+1,tmp));
}
main(){
对于(i=0;i
我不确定你所说的“分而治之”到底是什么意思。正如其他人所指出的,滑动窗口方法是O(n)
(你做得再好不过了,因为你需要至少看一次每个元素。)
你的解决方案很接近,除了你不必要地重新计算总和。这应该可以完成这项工作
void subvectorMin(int* v, int n, int m)
{
if (n < m)
{
std::cout << "Cannot calculate sub-vector m. (m<n)";
return; // return early
}
// compute the sum of first m elements
int sum = 0;
for(int i = 0; i < m; ++i)
sum += v[i];
// assume answer is at position 0
int pos = 0;
int min_sum = sum;
// check if there is a minimum sum somewhere else
for(int i = m; i < n; ++i)
{
sum = sum + v[i] - v[i - m]; // THIS is the sliding window that
// avoids the sum being recomputed
// if smaller sum is found, update the position
if(sum < min_sum)
{
min_sum = sum;
pos = i - m + 1;
}
}
std::cout << "The minimum component sum is: " << min_sum
<< " , subvector: {";
for(int i = pos; i < pos + m; ++i)
std::cout << " " << v[i];
std::cout << " }" <<std::endl;
}
void subvectorMin(int*v,int n,int m)
{
if(n std::cout我不确定你所说的“分而治之”到底是什么意思。正如其他人所指出的,滑动窗口方法是O(n)
(你做得再好不过了,因为你需要至少查看每个元素一次。)
你的解决方案很接近,除了你不必要地重新计算总和。这应该可以完成这项工作
void subvectorMin(int* v, int n, int m)
{
if (n < m)
{
std::cout << "Cannot calculate sub-vector m. (m<n)";
return; // return early
}
// compute the sum of first m elements
int sum = 0;
for(int i = 0; i < m; ++i)
sum += v[i];
// assume answer is at position 0
int pos = 0;
int min_sum = sum;
// check if there is a minimum sum somewhere else
for(int i = m; i < n; ++i)
{
sum = sum + v[i] - v[i - m]; // THIS is the sliding window that
// avoids the sum being recomputed
// if smaller sum is found, update the position
if(sum < min_sum)
{
min_sum = sum;
pos = i - m + 1;
}
}
std::cout << "The minimum component sum is: " << min_sum
<< " , subvector: {";
for(int i = pos; i < pos + m; ++i)
std::cout << " " << v[i];
std::cout << " }" <<std::endl;
}
void subvectorMin(int*v,int n,int m)
{
if(n std::我的想法是,将我的算法转换为分而治之,我在这张图片中是这样显示的:我认为我们应该做一些类似mergeSort的事情。谢谢你的回答。它的滑动窗口问题。从左到右划分。为什么你总是将滑动窗口划分为中间窗口?滑动的效率为O(n^2)我想通过分而治之来实现O(n*log(n))的效率。Thanks@Michael这里的滑动窗是O(n)因为在窗口的每一张幻灯片上,我们通过添加窗口的新的最后一个元素并减去O(1)中窗口的前一个元素来更新,最多迭代O(n)。我得到O(n^2)因为我返回总和旁边的子向量。我需要用分治法来做,到目前为止我的方法是这样的,但它在基本情况下给了我一个错误。我的想法是,将我的算法转换为分治法,我在这张图中的表现是:我想我们应该做一些类似mergeSort的事情。谢谢你的回答。它的滑动window问题。从左到右划分。为什么你总是划分为中间窗口滑动的效率为O(n^2),而我想通过分而治之实现O(n*log(n))的效率。我能够构建的方法如下,但我在基本情况下遇到了问题。Thanks@Michael这里的滑动窗是O(n)因为在窗口的每一张幻灯片上,我们通过添加窗口的新的最后一个元素并减去O(1)中窗口的前一个元素来更新,最多迭代O(n)。我得到O(n^2)因为我在求和的旁边返回子向量。我需要用分而治之的方法,到目前为止我的方法是这样的,但它在基本情况下给了我一个错误。谢谢你的回答,我需要用分而治之的方法来把大问题分解成小问题:-向量的前半部分:从0到center-向量的后半部分:从中心+1到n-检查最小数量是否通过中心我做了一些事情,但我不能很好地定义基本情况。我不确定为什么你有这个要求。当你的数据以这种方式重叠时,你将不得不在分区点做额外的工作。你能吗解释为什么必须这样做?感谢您的回复,我需要通过暴力(上面解释的windows滑动)和分而治之技术来分析这个问题。然后我将编写一份比较报告,并用windows sli来解释这一点