基于线性方程式计算值的算法

时间:2019-04-30 17:37:25

标签: java algorithm

我正在使用Java根据线性方程式计算PayStructure中各种Paycode的值。我的方程式如下:

CTC = Fixed Value
Basic = CTC * 0.4
HRA = Basic/2
ConveyanceAllowance = Fixed Value
ProvidentFund = Basic * 0.12
Gratuity = Basic * .0481
OtherAllowance = (CTC - (Basic + HRA + ConveyanceAllowance + ProvidentFund + Gratuity))

我尝试使用给定的here解决方案。但是,这种解决方案仅在所有计算得出的值都是整数的情况下才有效,在我的情况下,这些值也可以包含十进制数字。根据上述条件,我修改的代码如下:

public class PayStructure {

    public static void main(String[] args) {
        findAndprintSolutions(1, 1000000);
    }

    private static void findAndprintSolutions(int from, int to) {
        for (int a = from; a < to; a++) {
            for (int b = from; b < to; b++) {
                for (int c = from; c < to; c++) {
                    for (int d = from; d < to; d++) {
                        for (int e = from; e < to; e++) {
                            for (int f = from; f < to; f++) {
                                for (int g = from; g < to; g++) {
                                    if (isSolution(a, b, c, d, e, f, g))
                                        printSolution(new int[] { a, b, c, d, e, f, g });
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private static boolean isSolution(int a, int b, int c, int d, int e, int f, int g) {
        if (a != 100000)
            return false;
        if (b != a * (.4))
            return false;
        if (c != b / 2)
            return false;
        if (d != 10000)
            return false;
        if (e != b * (.12))
            return false;
        if (f != b * (.0481))
            return false;
        if (g != (a - (b + c + d + e + f)))
            return false;
        return true;
    }

    private static void printSolution(int[] variables) {
        StringBuilder output = new StringBuilder();
        for (int variable : variables) {
            output.append(variable + ", ");
        }
        output.deleteCharAt(output.length() - 1);
        output.deleteCharAt(output.length() - 1);
        System.out.println(output.toString());
    }

}

此外,上述代码将终止,因为CTC的最大值可能是数百万,并且根据变量的数量,时间复杂度最终将为millions^NumberOfVariables。是否有其他可能性可以根据给定的方程式计算值?方程和变量的数量可以变化,但是会有一个解决方案来计算每个变量的值,因此对于通用解的任何输入都会更好。

E.g.: If CTC = 100000 and ConveyanceAllowance = 10000, the code should return the output as:
Basic = 40000
HRA = 20000
ProvidentFund = 4800
Gratuity = 1924
OtherAllowance = 23276

3 个答案:

答案 0 :(得分:2)

也许最好的选择是弄清楚如何将其转化为c[1]x[1] + c[2]x[2] … + c[n]x[n] = 0形式的线性方程组。从那里,您可以使用广泛建立的线性系统技术来求解系统。有关更多信息,请参见Wikipedia页。您可以让用户以这种形式向您的方法提供输入,或者您可以对每个方程进行少量处理以对其进行转换(例如,如您的示例中,如果所有方程在LHS上都有一个变量,请翻转签名并将其放在RHS的末尾。

解释线性方程组系统的理论超出了此答案的范围,但是,基本上,您的系统将由唯一确定是否有一个有效分配,如果确定不存在有效分配,则过高确定,或者由无限多个确定分配是可能的。如果有一个唯一的分配,您将获得数字;如果系统不确定,您至少会得到一组必须包含无限多个解决方案的约束;如果不确定,您将一无所获,并且知道为什么。

答案 1 :(得分:1)

使用一些linear algebra library for Java。例如,使用记录在here中的矩阵运算来求解线性方程组。您的深层嵌套循环太慢,可以使用更好的算法。

答案 2 :(得分:0)

这就是我解决这个问题的方式。首先,我通过将所有变量放在左侧,将值&0放在右侧来创建方程式:

CTC = 1000000
(0.4)CTC - Basic = 0
(0.5)Basic-HRA = 0
ConvAll = 10000
(0.12)Basic-PF = 0
(0.0481)Basic - Gratuity = 0
CTC - (Basic + HRA + ConvAll + PF+ Gratuity + OtherAll) = 0

然后我创建了一个像这样的矩阵:

|1          0     0    0   0   0   0| |CTC     | = |1000000|
|0.4       -1     0    0   0   0   0| |Basic   | = |0      |
|0         0.5   -1    0   0   0   0| |HRA     | = |0
|0          0     0    1   0   0   0| |ConvAll | = |10000  |
|0         0.12   0    0  -1   0   0| |PF      | = |0      |
|0        0.0481  0    0   0  -1   0| |Gratuity| = |10000  |
|1         -1    -1   -1  -1  -1  -1| |OtherAll| = |0      |

此后,我使用下面的代码计算了(上述第一个矩阵的逆)和(最右边的矩阵)的乘积,并获得了每个分量的对应值:

public class Matrix

{
    static int n = 0;

    public static void main(String argv[]) {
        Scanner input = new Scanner(System.in);
        System.out.println("Enter the dimension of square matrix: ");

        n = input.nextInt();
        double a[][] = new double[n][n];
        System.out.println("Enter the elements of matrix: ");
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                a[i][j] = input.nextDouble();
        double d[][] = invert(a);
        System.out.println();
        System.out.println("Enter the equation values: ");
        System.out.println();
        double b[][] = new double[n][1];
        for (int i = 0; i < n; i++) {
            b[i][0] = input.nextDouble();
        }

        double e[][] = multiplyMatrix(d, b);
        System.out.println();
        System.out.println("The final solution is: ");
        System.out.println();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < 1; j++) {
                System.out.printf(e[i][j] + " ");
            }
            System.out.println();
        }
        input.close();
    }

    public static double[][] invert(double a[][]) {
        int n = a.length;
        double x[][] = new double[n][n];
        double b[][] = new double[n][n];
        int index[] = new int[n];
        for (int i = 0; i < n; ++i)
            b[i][i] = 1;

        // Transform the matrix into an upper triangle
        gaussian(a, index);

        // Update the matrix b[i][j] with the ratios stored
        for (int i = 0; i < n - 1; ++i)
            for (int j = i + 1; j < n; ++j)
                for (int k = 0; k < n; ++k)
                    b[index[j]][k] -= a[index[j]][i] * b[index[i]][k];

        // Perform backward substitutions
        for (int i = 0; i < n; ++i) {
            x[n - 1][i] = b[index[n - 1]][i] / a[index[n - 1]][n - 1];
            for (int j = n - 2; j >= 0; --j) {
                x[j][i] = b[index[j]][i];
                for (int k = j + 1; k < n; ++k) {
                    x[j][i] -= a[index[j]][k] * x[k][i];
                }
                x[j][i] /= a[index[j]][j];
            }
        }
        return x;
    }

    // Method to carry out the partial-pivoting Gaussian

    // elimination. Here index[] stores pivoting order.

    public static void gaussian(double a[][], int index[]) {
        int n = index.length;
        double c[] = new double[n];

        // Initialize the index
        for (int i = 0; i < n; ++i)
            index[i] = i;

        // Find the rescaling factors, one from each row
        for (int i = 0; i < n; ++i) {
            double c1 = 0;
            for (int j = 0; j < n; ++j) {
                double c0 = Math.abs(a[i][j]);
                if (c0 > c1)
                    c1 = c0;
            }
            c[i] = c1;
        }

        // Search the pivoting element from each column
        int k = 0;

        for (int j = 0; j < n - 1; ++j) {
            double pi1 = 0;
            for (int i = j; i < n; ++i) {
                double pi0 = Math.abs(a[index[i]][j]);
                pi0 /= c[index[i]];
                if (pi0 > pi1) {
                    pi1 = pi0;
                    k = i;
                }
            }

            // Interchange rows according to the pivoting order
            int itmp = index[j];
            index[j] = index[k];
            index[k] = itmp;
            for (int i = j + 1; i < n; ++i) {
                double pj = a[index[i]][j] / a[index[j]][j];
                // Record pivoting ratios below the diagonal
                a[index[i]][j] = pj;
                // Modify other elements accordingly
                for (int l = j + 1; l < n; ++l)
                    a[index[i]][l] -= pj * a[index[j]][l];
            }
        }
    }

    public static double[][] multiplyMatrix(double a[][], double b[][]) {
        double c[][] = new double[n][1];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < 1; j++) {
                for (int k = 0; k < n; k++) {
                    c[i][j] = c[i][j] + a[i][k] * b[k][j];
                }
            }
        }
        return c;
    }
}

谢谢大家的帮助。