划分黑白巧克力棒的算法

时间:2016-10-24 23:16:35

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

问题描述: 这是一个由m×n个正方形组成的巧克力棒。有些方块是黑色的,有些是白色的。有人沿着垂直轴或水平轴打破巧克力棒。然后它沿着它的垂直轴或水平轴再次被打破并且它被破坏直到它可以破碎成单个正方形或者它可以被分成仅黑色或仅白色的正方形。使用优选的分而治之算法,找出巧克力棒可以被破坏的方法的数量。

输入: 第一行告诉您巧克力棒的m x n尺寸。在接下来的m行中,有n个字符可以告诉您巧克力棒的外观。字母w是白色方块,字母b是黑色方块。 例如: 3 2 BWB WBW

输出: 巧克力棒可以破碎的方法数量: 对于上面的例子,它是5(看看附图)。

example

我尝试使用迭代方法解决它。不幸的是,我无法完成代码,因为我还不确定如何划分这两半(请参阅下面的代码)。我被告知,递归方法比这更容易,但我不知道如何做到这一点。我正在寻找另一种方法来解决这个问题而不是我的方法,或者我正在寻找一些帮助来完成我的代码。

我制作了两个2D阵列,第一个用于白色方块,第二个用于黑色方块。我在正方形中制作矩阵,如果有这样或那种颜色的巧克力,那么我在相应的数组中将其标记为1。 然后我制作了上面两个矩阵累积和的两个数组。 然后我创建了一个大小为[n] [m] [n] [m]的4D数组,我做了4个循环:前两个(i,j)增加了一个矩形数组的大小,这个数组是搜索数组的大小(很难解释......)还有两个循环(k,l)增加了我的起点x和y在数组中的位置。然后算法检查使用累积和,如果在从位置kx1开始并且在k + i x l + j结束的区域中,则存在一个黑色和一个白色方块。如果有,那么我创建两个将该区域分成两半的循环。如果在两个新的一半中仍然存在黑色和白色方块,那么我将相应的4D数组元素增加前半部分的组合数*第二半的组合数。

    #include <iostream>
    #include <fstream>

    using namespace std;

    int main()
    {
        int counter=0;
        int n, m;
        ifstream in;
        in.open("in.txt");
        ofstream out;
        out.open("out.txt");
        if(!in.good())
        {
            cout << "No such file";
            return 0;
        }
        in >> n >> m;

        int whitesarray[m][n];
        int blacksarray[m][n];
        int methodsarray[m][n][m][n];

        for(int i=0; i<m; i++)
        {
            for(int j=0; j<n; j++)
            {
                whitesarray[i][j] = 0;
                blacksarray[i][j] = 0;
            }
       }

        while(in)
        {
            string colour;
            in >> colour;
            for (int i=0; i < colour.length(); i++)
            {
                if(colour[i] == 'c')
                {
                    blacksarray[counter][i] = 1;
                }
                if(colour[i] == 'b')
                {
                    whitesarray[counter][i] = 1;
                }
            }
            counter++;
        }

        int whitessum[m][n];
        int blackssum[m][n];


    for (int i=0; i<m; i++)
    {
        for (int j=0; j<n; j++)
        {
            if(i-1 == -1 && j-1 == -1)
            {
                whitessum[i][j] = whitesarray[i][j];
                blackssum[i][j] = blacksarray[i][j];
            }
            if(i-1 == -1 && j-1 != -1)
            {
                whitessum[i][j] = whitessum[i][j-1] + whitesarray[i][j];
                blackssum[i][j] = blackssum[i][j-1] + blacksarray[i][j];
            }
            if(j-1 == -1 && i-1 != -1)
            {
                whitessum[i][j] = whitessum[i-1][j] + whitesarray[i][j];
                blackssum[i][j] = blackssum[i-1][j] + blacksarray[i][j];

            }
            if(j-1 != -1 && i-1 != -1)
            {
                whitessum[i][j] = whitessum[i-1][j] + whitessum[i][j-1] - whitessum[i-1][j-1] + whitesarray[i][j];
                blackssum[i][j] = blackssum[i-1][j] + blackssum[i][j-1] - blackssum[i-1][j-1] + blacksarray[i][j];
            }
                }
    }


    int posx=0;
    int posy=0;
    int tempwhitessum=0;
    int tempblackssum=0;
    int k=0, l=0;

    for (int i=0; i<=m; i++)
    {
        for (int j=0; j<=n; j++) // wielkosc wierszy
        {
            for (posx=0; posx < m - i; posx++)
            {
                for(posy = 0; posy < n - j; posy++)
                {
            k = i+posx-1;
            l = j+posy-1;
            if(k >= m || l >= n)
                continue;
            if(posx==0 && posy==0)
            {
                tempwhitessum = whitessum[k][l];
                tempblackssum = blackssum[k][l];

            }
            if(posx==0 && posy!=0)
            {
                tempwhitessum = whitessum[k][l] - whitessum[k][posy-1];
                tempblackssum = blackssum[k][l] - blackssum[k][posy-1];

            }
            if(posx!=0 && posy==0)
            {
                tempwhitessum = whitessum[k][l] - whitessum[posx-1][l];
                tempblackssum = blackssum[k][l] - blackssum[posx-1][l];

            }
            if(posx!=0 && posy!=0)
            {
                tempwhitessum = whitessum[k][l] - whitessum[posx-1][l] - whitessum[k][posy-1] + whitessum[posx-1][posy-1];
                tempblackssum = blackssum[k][l] - blackssum[posx-1][l] - blackssum[k][posy-1] + blackssum[posx-1][posy-1];

            }
       if(tempwhitessum >0 && tempblackssum > 0)
       {
            for(int e=0; e<n; e++)
            {
                //Somehow divide the previously found area by two and check again if there are black and white squares in this area
            }
            for(int r=0; r<m; r++)
            {
                //Somehow divide the previously found area by two and check again if there are black and white squares in this area

            }
       }
                }
            }
        }}

        return 0;
    }

1 个答案:

答案 0 :(得分:3)

我强烈建议递归。实际上,动态编程(DP)也非常有用,特别是对于较大的条形图。先递归...

<强>递归

您的递归例程需要一个二维字符数组( b w )。它返回了可以破解的方式。

首先,基本情况:(1)如果可以将给定的条形分成一个单独的部分(参见上面的评论,要求澄清),返回1; (2)如果数组是全部一种颜色,则返回1.对于每一种颜色,只有一种方法可以使条形结束 - 传递方式。

现在,对于更复杂的情况,当条形图仍然可以被破坏时:

total_ways = 0
for each non-edge position in each dimension:
    break the bar at that spot; form the two smaller bars, A and B.
    count the ways to break each smaller bar: count(A) and count(B)
    total_ways += count(A) * count(B)
return total_ways

对于一般方法来说,这是否足够清楚?你仍然有很多编码要做,但是使用递归可以让你在编写函数时只考虑两个基本思想:(1)我怎么知道我什么时候完成,然后我又回到了什么微不足道的结果? (2)如果我没有完成,我该如何减少这个问题呢?

动态编程

这包括记录您已经解决的情况。您在例程中做的第一件事是检查您的“数据库”,看看您是否已经知道这种情况。如果是,则返回已知结果而不是重新计算。这包括开发和实现所述数据库的开销,可能是字符串数组和整数结果的查找列表(字典),例如[“bwb”,“wbw”] =&gt; 5。