Algorithm 箱子包装解决方案:这是怎么回事?

Algorithm 箱子包装解决方案:这是怎么回事?,algorithm,matrix,np-complete,Algorithm,Matrix,Np Complete,我已经尝试实现了一个解决方案,主要是以这种方式。我不做Haskell,所以我用C++编写了一些东西。 对于小于某个数字36的墙宽度,我的程序和Haskell程序给出了相同的结果。对于任何36个单位宽或更宽的墙,我的结果要低得多。我怀疑我的解决方案是否正确,因为另一张海报在这里很有代表性。我认为问题在于我的位矩阵中填充的1的数量比应该的要少得多 #include <vector> #include <iostream> #include <algorithm>

我已经尝试实现了一个解决方案,主要是以这种方式。我不做Haskell,所以我用C++编写了一些东西。 对于小于某个数字36的墙宽度,我的程序和Haskell程序给出了相同的结果。对于任何36个单位宽或更宽的墙,我的结果要低得多。我怀疑我的解决方案是否正确,因为另一张海报在这里很有代表性。我认为问题在于我的位矩阵中填充的1的数量比应该的要少得多

#include <vector>
#include <iostream>
#include <algorithm>

const int NARROW_W = 6;     // 3
const int WIDE_W = 9;       // 4.5

const int MIN_WALL_W = 6;   // 3
const int MAX_WALL_W = 96;  // 48
const int MIN_WALL_H = 1;
const int MAX_WALL_H = 10;

// precomputed factorials for finding # of combos
static const long long fact[] =
{
    1,
    1,
    2,
    6,
    24,
    120,
    720,
    5040,
    40320,
    362880,
    3628800,
39916800,
479001600,
6227020800
};

using namespace std;

typedef vector<unsigned long long> LongVec;
typedef vector< vector<int> > IntMat;

LongVec operator * (const IntMat &a, const LongVec &b); // O(n^2)

int main(int argc, char** argv)
{
    int i, j, k;
    int width, height;
    int lcm; // Lowest Common Multiple
    int narrowc, widec;
    bool valid;
    unsigned rowc;
    IntMat bit_mat, gap_vecs, block_vecs;
    vector<int> gaps, blocks;
    vector<int>::iterator it;
    unsigned long long result;
    LongVec vec_res;

    if (argc < 3)
    {
        cerr << "Usage: " << argv[0] << " [width] [height]\n";
        exit(EXIT_FAILURE);
    }
    width = (int) (strtod(argv[1], NULL) * 2);
    height = (int) strtod(argv[2], NULL);
    if (width < MIN_WALL_W || width > MAX_WALL_W)
    {
        cerr << "Width out of range\n";
        exit(EXIT_FAILURE);
    }
    if (height < MIN_WALL_H || height > MAX_WALL_H)
    {
        cerr << "Height out of range\n";
        exit(EXIT_FAILURE);
    }

    // see if valid row is possible
    // by removing narrows and adding wides until width is reached
    narrowc = width / NARROW_W;
    widec = 0;
    valid = false;
    if (width % NARROW_W > 0)
    {
        while (narrowc > 0 && !valid)
        {
            narrowc--;
            widec = 0;
            do
                widec++;
            while ((widec * WIDE_W) + (narrowc * NARROW_W) < width);
            if ((widec * WIDE_W) + (narrowc * NARROW_W) == width)
                valid = true;
        }
    }
    else valid = true;
    if (!valid)
    {
        cout << 0;
        exit(EXIT_SUCCESS);
    }

    // find valid rows
    lcm = WIDE_W;
    while (lcm % WIDE_W != 0 || lcm % NARROW_W != 0)
        lcm++;
    rowc = 0;
    while (narrowc >= 0)
    {
        rowc += (unsigned) (fact[narrowc + widec] /
            (fact[narrowc] * fact[widec]));

        block_vecs.reserve(rowc);
        gap_vecs.reserve(rowc);

        blocks.clear();
        for (j = 0; j < narrowc; j++)
        {
            blocks.push_back(NARROW_W);
        }
        for (j = 0; j < widec; j++)
        {
            blocks.push_back(WIDE_W);
        }
        block_vecs.push_back(blocks);

        gap_vecs.push_back(blocks);
        for (j = 1; j < gap_vecs.back().size() - 1; j++)
        {
            gap_vecs.back().at(j) += gap_vecs.back().at(j - 1);
        }
        gap_vecs.back().pop_back();

        if (widec > 0 && narrowc > 0)
        {
            while (next_permutation(blocks.begin(), blocks.end()))
            {
                block_vecs.push_back(blocks);

                gap_vecs.push_back(blocks);
                for (j = 1; j < gap_vecs.back().size() - 1; j++)
                {
                    gap_vecs.back().at(j) += gap_vecs.back().at(j - 1);
                }
                gap_vecs.back().pop_back();
            }
        }

        narrowc -= lcm / NARROW_W;
        widec += lcm / WIDE_W;
    }

    // fill bit matrix
    bit_mat.reserve(rowc);
    vector<int> v(gap_vecs.at(0).size() * 2);
    for (i = 0; i < rowc; i++)
    {
        gaps.clear();
        bit_mat.push_back(gaps);
        gaps = gap_vecs.at(i);
        for (j = 0; j < rowc; j++)
        {
            //v.clear();
            it = set_intersection(gaps.begin(), gaps.end(),
                    gap_vecs.at(j).begin(), gap_vecs.at(j).end(), v.begin());
            if ((int) (it - v.begin()) != 0)
            {
                bit_mat.back().push_back(0);
            }
            else
            {
                bit_mat.back().push_back(1);
            }
        }
    }

    // multiply vector of 1's by bit matrix (height - 1) times
    vec_res.assign(rowc, 1);
    for (i = 0; i < height - 1; i++)
    {
        vec_res = bit_mat * vec_res;
    }
    result = 0;
    for (i = 0; i < vec_res.size(); i++)
        result += vec_res.at(i);

    cout << result;

    exit(EXIT_SUCCESS);
}

LongVec operator * (const IntMat &a, const LongVec &b)
{
    int i, j;
    int m = a.size();
    int n = b.size();

    LongVec result(m);

    for (i = 0; i < m; i++)
    {
        result[i] = 0;
        for (j = 0; j < n; j++)
        {
            result[i] += a[i][j] * b[j];
        }
    }
    return result;
}
我怀疑,如果这没有给出正确的解决方案,set_intersection函数就没有做它应该做的事情,看看两组间隙索引之间是否有匹配。有什么想法吗?我正在Mac OS X 10.8上使用g++进行编译

// precomputed factorials for finding # of combos
static const long long fact[] =
{
    1,
    1,
    2,
    6,
    24,
    120,
    720,
    5040,
    40320,
    362880,
    3628800,
    39916800,
    479001600,
    6227020800
};
您缺少了一些阶乘,在

   rowc += (unsigned) (fact[narrowc + widec] /
        (fact[narrowc] * fact[widec]));
你可能需要16个!为了你的极限。加

              ,
    87178291200,
    1307674368000,
    20922789888000

在适当的位置。

只是一个猜测,但可能您使用的是32位数字,当您达到宽度37时,一些数字溢出。哦,箱子的包装也不一样。@rici谢谢;我将稍微处理一下数据类型。不过,对于48x10墙,矩阵元素3329x3329的数量适合32位。@rici不会发生溢出,因为使用-ftrapv进行编译会得到相同的结果。很好,尽管我实际上删除了整个阶乘业务,因为行计数是通过每次向向量向量添加间隙排列时递增来计算的。嗯,加上这一点,它为我吐出了正确的值,不是吗?