【问题标题】:Count of an element in a matrix using Divide & Conquer使用分治法计算矩阵中的元素
【发布时间】:2015-09-05 00:58:16
【问题描述】:

我开始学习如何实现分而治之的算法,但我在这个练习中遇到了一些问题。

我已经编写了一个算法,但不幸的是它返回了一个 0 值。我需要使用 D&C 计算一个数字在矩阵中找到的次数。

我的想法是将矩阵分成4个子矩阵,直到所有坐标都相等,这意味着有一个元素(可以是我的数字也可以不是)。

我的缩写:

lr - left row   | starting with 
lc- left column | left lower corner
rr - right row    | starting with
rc- right column  |  right upper corner

当我编译时,它运行良好但返回 0(我认为是因为我的 stop 语句)。 所以,我的错误在于solve() 函数。

我的代码:

#include<fstream>
#include<conio.h>
#include<iostream>
using namespace std;
ifstream fin("in.txt");
#define debug cerr<<"OK";
int n,a[100][100];
int solve(int lr,int lc, int rr,int rc,int x,int &contor)
{
    int cnt=0;
    if(lr < rr || lc > rc)
    {
        if(cnt<=0)
            return 0;
        return cnt;
    }
        if(lr == lc && rr == rc)
        if(a[lr][lc] == x)
            cnt++;
        else;
    else
    {
        int l=(lr+rr)/2;
        int c=(lc+rc)/2;
        if(l && c)
        {
        int cnt1=solve(lr-l,lc,rr,rc-c,x,contor); // coordinates for upper left square
        int cnt2=solve(lr-l,lc+c,rr,rc,x,contor); // -||- for upper right square
        int cnt3=solve(lr,lc,rr+l,rc-c,x,contor); // -||- for low left square 
        int cnt4=solve(lr,lc+c,rr,rc-c,x,contor); // -||- for low right square
        contor=cnt1+cnt2+cnt3+cnt4;
        }
    }
}

int main()
{  
    fin>>n;
    int i,j;
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        fin>>a[i][j];
    int contor=0;
solve(n,1,1,n,3,contor);  // i'm searching for 3
   cout<<contor;
    _getch();
   fin.close();
   return 0;
}

也许你可以告诉我问题出在哪里或者直接解决,这样会更快,我也更容易理解。

Input:
4
1 3 3 4
5 6 7 8
1 2 3 4
4 3 2 1

【问题讨论】:

  • cnt 不应是全局变量。相反,您应该返回相应的值(在进行除法时将子调用的返回值相加)。而且,划分坐标看起来有些奇怪。左上角不应该只是lr, l, lc, c吗?更有意义的变量命名是可取的,这样其他人(包括一周内的您)可以理解您的意思。
  • 我上面评论的坐标可能是错误的。您的命名约定对我来说太混乱了。我的建议:min1max1 用于第一个维度,min2max2 用于第二个维度。另一个错误是您的初始化。数组索引是从零开始的,因此您应该指定从0n-1 的区域。
  • 好的,谢谢,我试过了,但是当我回答@marom 时,我得到了一个非常大的数字。是的,他们错了,我写得很清楚,我从左下角和右上角开始。我知道,但我从索引 1 开始,以便更容易计算行数和列数。
  • 但是如果你从 1 开始,你访问的是错误的数组元素。因为cnt 未初始化为0,您可能会得到大量数字。如果cnt 不是全局变量,这个问题甚至不会存在。
  • 我修改了我的代码,现在呢?我仍然得到很多

标签: c++ algorithm matrix divide-and-conquer


【解决方案1】:

这是更正后的源代码。我添加了一些 cmets,以便您可以关注它。此外,我切换到正确大小的动态数组。

#include<fstream>
#include<conio.h>
#include<iostream>

using namespace std;

int countOccurences(int** values, int min1, int min2, int max1, int max2, int searchValue)
{
    if (min1 > max1 || min2 > max2)
        return 0; //invalid area

    if (min1 == max1 && min2 == max2)
    {
        //the current area is a single cell
        if (values[min1][min2] == searchValue)
            return 1; //we have found 1 occurence
        else
            return 0; //we have found nothing
    }
    else
    {
        //divide the current range
        int center1 = (min1 + max1) / 2;
        int center2 = (min2 + max2) / 2;

        int occurencesInSubMatrices = 0;

        //accumulate the occurences in the according variable
        occurencesInSubMatrices += countOccurences(values, min1, min2, center1, center2, searchValue); // coordinates for upper left square
        occurencesInSubMatrices += countOccurences(values, center1 + 1, min2, max1, center2, searchValue); // -||- for upper right square
        occurencesInSubMatrices += countOccurences(values, min1, center2 + 1, center1, max2, searchValue); // -||- for low left square 
        occurencesInSubMatrices += countOccurences(values, center1 + 1, center2 + 1, max1, max2, searchValue); // -||- for low right square
        return occurencesInSubMatrices;
    }
}

int main()
{
    ifstream fin("in.txt");
    int n;
    fin >> n;

    //create a 2d array of appropriate size
    int** values = new int*[n];

    for (int i = 0; i < n; i++)
    {
        //allocate memory for the i-th row
        values[i] = new int[n];
        for (int j = 0; j < n; j++)
            fin >> values[i][j];
    }

    int count = countOccurences(values, 0, 0, n - 1, n - 1, 3);  // i'm searching for 3
    cout << count;
    _getch();
    fin.close();
    return 0;
}

请注意,这是一个纯粹的教育示例。在现实世界中,没有人会这样计算发生次数。

【讨论】:

  • 当然不是,只是为了更好地理解D&C的概念!谢谢
  • 还有一件事,你为什么要用int**?
  • 称为锯齿数组。每行都是一个一维数组(指向 int 的指针,即int*)。二维数组基本上是这些数组的一维数组(int* 的数组,因此是int**)。
  • 好吧,还有一个问题,为什么你对最小值和最大值使用相同的坐标?我的意思是你从哪个角落开始 min1 & max1 和 min2 & max2?哪个是行,哪个是列?
  • 因为两个维度(水平和垂直)具有相同的范围(最小值 = 0,最大值 = n-1)。行和列的概念取决于解释。输入文件中的行在第一个维度上具有相同的坐标。因此,第一个维度指定行,第二个维度指定列。
【解决方案2】:

递归不更新cnt...

    if(l && c)
    {
    solve(lr-l,lc,rr,rc-c,x); // coordinates for upper left square 
    solve(lr-l,lc+c,rr,rc,x); // -||- for upper right square
    solve(lr,lc,rr+l,rc-c,x); // -||- for low left square 
    solve(lr,lc+c,rr,rc-c,x); // -||- for low right square
    }

【讨论】:

  • 我尝试了一些东西,但现在我得到了一个非常大的数字!您可以编辑您的帖子并使其更具相关性吗?
猜你喜欢
  • 2019-03-13
  • 2020-06-12
  • 2011-06-18
  • 2014-08-24
  • 2016-08-16
  • 1970-01-01
  • 1970-01-01
  • 2013-07-02
  • 2017-12-05
相关资源
最近更新 更多