【问题标题】:Finding solutions to a single linear equation in n variables, or determine that no solution exists在 n 个变量中寻找单个线性方程的解,或确定不存在解
【发布时间】:2013-09-27 18:10:04
【问题描述】:

假设你有一个包含 n 个变量的线性方程。目标是要么确定不可能有整数解,要么确定整数解的最小系数向量。

换句话说,让ax=b 其中x 是您要查找的向量,a 是系数向量。 b 是一个标量常数。找到x 使得x1, ... ,xn 的和最小化,并且所有xis 都是整数。或者,确定不存在这样的x。从现在开始,我会说|x|xi的总和。

解决这个问题的有效方法是什么?我觉得这类似于背包问题,但我并不完全确定。

我的解决方案

我试图解决这个问题的方法是对向量​​空间进行广度优先搜索,其中 breadth 将是向量条目的总和。

一开始我很天真,从|x| = 0开始,但是当n甚至中等大,并且解决方案不平凡时,生成的向量数量是巨大的(n ^ |x|每个|x|你通过)。更糟糕的是,我生成了许多重复项。即使我找到了一种几乎不产生重复的方法,这种方法也太慢了。

接下来,我尝试从更高的|x| 开始,在最佳|x| 上设置下限。我对a 进行了排序,使其按降序排列,然后删除了所有ai > b。那么|x| 的下限是b / a[0]。但是,从这一点开始,我很难快速生成所有大小为|x| 的向量。从这里开始,我的代码大多是 hacky。

在代码中,b = distancex = clubsn = numClubs

这是它的样子:

short getNumStrokes (unsigned short distance, unsigned short numClubs, vector<unsigned short> clubs) {
    if (distance == 0)
        return 0;

    numClubs = pruneClubs(distance, &clubs, numClubs);
    //printClubs (clubs, numClubs);

    valarray<unsigned short> a(numClubs), b(numClubs);
    queue<valarray<unsigned short> > Q; 

    unsigned short floor = distance / clubs[0];

    if (numClubs > 1) {
        for (int i = 0; i < numClubs; i++) {
            a[i] = floor / numClubs;
        }

        Q.push (a);
    }

    // starter vectors
    for (int i = 0; i < numClubs; i++) {
        for (int j = 0; j < numClubs; j++) {
            if (i == j)
                a[j] = distance / clubs[0];
            else
                a[j] = 0;
        }

        if (dot_product (a, clubs) == distance)
            return count_strokes(a);

        // add N starter values
        Q.push (a);
    }

    bool sawZero = false;

    while (! Q.empty ()) {
        a = Q.front(); // take first element from Q
        Q.pop(); // apparently need to do this in 2 operations >_<

        sawZero = false;

        for (unsigned int i = 0; i < numClubs; i++) {
            // only add numbers past right-most non-zero digit
            //if (sawZero || (a[i] != 0 && (i + 1 == numClubs || a[i + 1] == 0))) {
            //    sawZero = true;

                b = a; // deep copy
                b[i] += 1;

                if (dot_product (b, clubs) == distance) {
                    return count_strokes(b);
                } else if (dot_product (b, clubs) < distance) {
                    //printValArray (b, clubs, numClubs);
                    Q.push (b);
                }
            //}
        }
    }

    return -1;
}

编辑:我使用 valarray 因为我的编译器不符合 C++ 11,所以我不能使用数组。其他代码建议非常感谢。

【问题讨论】:

  • 只需使用pseudoinverse?
  • @OliCharlesworth 不要认为我们在数值计算中涵盖了这一点。你能解释一下我 5 岁吗?
  • 线性方程存在于线性空间中。由自然数组成的向量不形成线性空间。
  • @BlackSheep:啊,您应该在问题中明确说明!
  • “Bread-First Search” - 我每天早上的例行公事。

标签: c++ algorithm math language-agnostic


【解决方案1】:

你的问题是一个等式约束整数背包问题:

min |x|
s.t. ax = b
     x integer

如果您有访问权限,CPLEX 或 GUROBI 通常可以很容易地解决此类问题。

否则,考虑对约束集进行一些缩减

(例如,http://www.optimization-online.org/DB_FILE/2002/11/561.ps

【讨论】:

  • glpk,GNU 线性规划工具包,是一个免费的解决方案。
  • @Paul Rubel 很重要。我认为 coin-or 也有一些开源解决方案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多