匈牙利算法的最后一步遇到了麻烦(找到一组零的算法)

时间:2018-12-06 16:11:10

标签: java algorithm

http://www.hungarianalgorithm.com/examplehungarianalgorithm.php

我已经实现了所有步骤,直到最后一步,其中覆盖所有零(nxn矩阵的n)所需的最小行数。

最初,我计划进行一个贪婪的选择,我将逐列遍历2d数组并选择找到的第一个零。很快,发现这是一个糟糕的主意,甚至对我的小型5x5矩阵也不起作用(真正的东西很可能是n约为100-200的矩阵)。

每个列和行只能选择一个零。例如,假设选择了一个成本为[0] [1]的零,则无法在第0行或第1列中选择其他零(因为该算法将1个“工人”匹配到1个“工作”)。

对于矩阵成本(成本已被处理成最终形式):

{1 0 3 2 2
 0 1 3 1 3
 5 4 4 0 0
 1 0 0 1 1
 0 1 0 0 2}

使用“贪婪选择”,输出将为

int[] matched = new int[costs.length]{1, 0, 3, 2, 2};//Array stores column index of the zeros.

很明显,选择成本为零的成本[4] [3]是理想的选择,而不是贪婪地选择成本[2] [3],因为您随后可以选择成本[2] [4]。有人知道我可以实施一个相对简单的选择算法来解决这个问题吗?

如果您有兴趣,这是到目前为止的课程(我省略了不太相关的代码):

public class HungarianAlgorithm {
private int[][] costMatrix;//Untouched, original matrix, will not be changed during runtime.
private final int zeroCoveredOnce = 100;//The value used during the draw lines step to indicate that a position in int[][] cost has been covered once with a line. To indicate it has been covered twice, use 2x this value.

public HungarianAlgorithm(int[][] costMatrix)
{
    this.costMatrix = costMatrix;
}

public int[] execute()
{
    int[][] costs = costMatrix;//costs will be changed through execution.
    Covering covering;
    int lineCount;

    costs = initialReduction(costs);
    covering = coverZeros(costs);
    costs = covering.returnCosts();
    lineCount = covering.returnLineCount();

    while(lineCount < costs.length)
    {
        costs = furtherReduction(costs);
        covering = coverZeros(costs);
        costs = covering.returnCosts();
        lineCount = covering.returnLineCount();
    }
    return null;
}

private int[] assignment(int[][] costs)//The problematic one.
{
    int[] assignment;

    return null;
}

private int[][] initialReduction(int[][] costs)//Reduces rows, then columns. Perhaps should separate them but who knows we'll see.
{
    int[] minOfRows = new int[costs[0].length];//int array of the lowest cost in each row of array
    int[] minOfColumns = new int[costs.length];
    minOfRows = returnRowMins(costs);
    int tempRowCount = 0;

    for(int[] row: costs)
    {
        for(int i: row)
        {
            i = i - minOfRows[tempRowCount];
        }
        tempRowCount++;
    }

    minOfColumns = returnColumnMins(costs);

    for(int j = 0; j < costs.length; j++)
    {
        if(checkZerosInColumn(costs, j) == false)
        {
            for(int k = 0; k < costs.length; k++)
            {
                costs[k][j] = costs[k][j] - minOfColumns[j];
            }
        }
    }
    return costs;
}

private int[][] furtherReduction(int[][] costs)
{
    int smallest = findSmallestUncoveredNumber(costs);

    for(int[] row: costs)
    {
        for(int value: row)
        {
            if(value == zeroCoveredOnce*2)
            {
                value = value + smallest;
            }
            if(value != zeroCoveredOnce && value != zeroCoveredOnce*2)
            {
                value = value - smallest;
            }
        }
    }

    return costs;
}

private int findSmallestUncoveredNumber(int[][] costs)
{
    int smallest = 0;

    for(int i = 0; i < costs.length; i++)
    {
        smallest = smallest + costs[0][i];
    }

    for(int[] row: costs)
    {
        for(int value: row)
        {
            if(value < smallest)
            {
                smallest = value;
            }
        }
    }

    return smallest;
}

private Covering coverZeros(int[][] costs)
{
    int lineCount = 0;
    Covering covering;

    for(int i = 0; i < costs.length; i++)
    {
        for(int j = 0; j < costs.length; j++)
        {
            if(costs[i][j] == 0)
            {
                costs = drawLines(costs, i, j);
                ++lineCount;
            }
        }
    }

    covering = new Covering(costs, lineCount);

    return covering;
}

private int[][] drawLines(int[][] costs, int x, int y)
{
    int orientation = determineOrientation(costs, x, y);

    for(int i = 0; i < costs.length; i++)
    {
        if(orientation > 0)
        {
            if(costs[x][i] == zeroCoveredOnce)
            {
                costs[x][i] = zeroCoveredOnce*2;
            }
            if(costs[x][i] != zeroCoveredOnce && costs[x][i] != zeroCoveredOnce*2)
            {
                costs[x][i] = zeroCoveredOnce;
            }
        }
        else
        {
            if(costs[i][y] == zeroCoveredOnce)
            {
                costs[i][y] = zeroCoveredOnce*2;
            }
            if(costs[i][y] != zeroCoveredOnce && costs[i][y] != zeroCoveredOnce*2)
            {
                costs[i][y] = zeroCoveredOnce;
            }
        }
    }

    return costs;
}

private int determineOrientation(int[][] costs, int x, int y)
{
    int indicator = 0;//Increment for row zeros, decrement for column zeros.

    for(int i = 0; i < costs.length; i++)
    {
        if(costs[x][i] == 0)
        {
            ++indicator;
        }
        if(costs[i][y] == 0)
        {
            --indicator;
        }
    }

    return indicator;
}

private boolean checkZerosInColumn(int[][] costs, int columnNumber)//Iterates through costs[n][columnNumber] and returns true and terminates the current for loop whenever there are zeros.
{
    boolean hasZeros = false;
    for(int i = columnNumber; i < costs.length; i++)
    {
        for(int j = 0; j < costs[columnNumber].length; j++)
        {
            if(costs[j][i] == 0)
            {
                hasZeros = true;
                break;
            }
        }
    }
    return hasZeros;
}

private int[] returnRowMins(int[][] costs);

private int[] returnColumnMins(int[][] costs);

public int[][] returnCostMatrix();

public void setCostMatrix(int[][] costMatrix);

}

0 个答案:

没有答案