📌  相关文章
📜  最大限度地减少彼此借钱的给定朋友之间的现金流量

📅  最后修改于: 2021-04-26 07:37:15             🧑  作者: Mango

给了一些必须互相赠与或取钱的朋友。设计一种算法,以使所有好友之间的总现金流量最小化。
例子:
下图显示了要清算的输入债务。

现金周转

以上债务可以通过以下优化方式进行清算

现金周转

这个想法是使用贪婪算法,其中每一步都要解决一个人的全部金额,然后再为剩下的n-1个人进行递归。
如何挑选第一人称?要选择第一个人,请通过从所有贷项(要付的金额)中减去所有债务(要付的金额)来计算获得净额的每个人的净额。一旦对每个人的净额进行了评估,就找到两个净额最大和最小的人。这两个人是债权人和债务人最多的人。最少两个人是我们第一个被解决并从名单中删除的人。设两个数量的最小值为x。我们从最大债务人向最大债权人支付“ x”金额,并结清一个人。如果x等于最大借方,则清算最大债务人,否则清算最大债权人。
以下是详细的算法。
对我从0到n-1的每个人Pi进行跟踪。
1)计算每个人的净额。人“ i”的净额可以通过从所有贷项的总和中减去所有债务的总和来计算。
2)找到最大债权人和最大债务人两个人。设要记入最大债权人的最大金额为maxCredit,从最大债务人借记的最大金额为maxDebit。设最大债务人为Pd,最大债权人为Pc。
3)找到maxDebit和maxCredit的最小值。设两个最小值为x。从Pd借记“ x”,然后将此金额记入Pc
4)如果x等于maxCredit,则从一组人员中删除Pc,然后对剩余的(n-1)个人进行重复操作。
5)如果x等于maxDebit,则从人员集中删除Pd,然后对剩余的(n-1)个人重复操作。
感谢Balaji S在此处的评论中建议此方法。
以下是上述算法的实现。

C++
// C++ program to fin maximum cash flow among a set of persons
#include
using namespace std;
 
// Number of persons (or vertices in the graph)
#define N 3
 
// A utility function that returns index of minimum value in arr[]
int getMin(int arr[])
{
    int minInd = 0;
    for (int i=1; i arr[maxInd])
            maxInd = i;
    return maxInd;
}
 
// A utility function to return minimum of 2 values
int minOf2(int x, int y)
{
    return (x


Java
// Java program to fin maximum cash
// flow among a set of persons
 
class GFG
{
    // Number of persons (or vertices in the graph)
    static final int N = 3;
     
    // A utility function that returns
    // index of minimum value in arr[]
    static int getMin(int arr[])
    {
        int minInd = 0;
        for (int i = 1; i < N; i++)
            if (arr[i] < arr[minInd])
                minInd = i;
        return minInd;
    }
     
    // A utility function that returns
    // index of maximum value in arr[]
    static int getMax(int arr[])
    {
        int maxInd = 0;
        for (int i = 1; i < N; i++)
            if (arr[i] > arr[maxInd])
                maxInd = i;
        return maxInd;
    }
     
    // A utility function to return minimum of 2 values
    static int minOf2(int x, int y)
    {
        return (x < y) ? x: y;
    }
     
    // amount[p] indicates the net amount
    // to be credited/debited to/from person 'p'
    // If amount[p] is positive, then
    // i'th person will amount[i]
    // If amount[p] is negative, then
    // i'th person will give -amount[i]
    static void minCashFlowRec(int amount[])
    {
        // Find the indexes of minimum and
        // maximum values in amount[]
        // amount[mxCredit] indicates the maximum amount
        // to be given (or credited) to any person .
        // And amount[mxDebit] indicates the maximum amount
        // to be taken(or debited) from any person.
        // So if there is a positive value in amount[],
        // then there must be a negative value
        int mxCredit = getMax(amount), mxDebit = getMin(amount);
     
        // If both amounts are 0, then
        // all amounts are settled
        if (amount[mxCredit] == 0 && amount[mxDebit] == 0)
            return;
     
        // Find the minimum of two amounts
        int min = minOf2(-amount[mxDebit], amount[mxCredit]);
        amount[mxCredit] -= min;
        amount[mxDebit] += min;
     
        // If minimum is the maximum amount to be
        System.out.println("Person " + mxDebit + " pays " + min
                                + " to " + "Person " + mxCredit);
     
        // Recur for the amount array.
        // Note that it is guaranteed that
        // the recursion would terminate
        // as either amount[mxCredit]  or
        // amount[mxDebit] becomes 0
        minCashFlowRec(amount);
    }
     
    // Given a set of persons as graph[]
    // where graph[i][j] indicates
    // the amount that person i needs to
    // pay person j, this function
    // finds and prints the minimum
    // cash flow to settle all debts.
    static void minCashFlow(int graph[][])
    {
        // Create an array amount[],
        // initialize all value in it as 0.
        int amount[]=new int[N];
     
        // Calculate the net amount to
        // be paid to person 'p', and
        // stores it in amount[p]. The
        // value of amount[p] can be
        // calculated by subtracting
        // debts of 'p' from credits of 'p'
        for (int p = 0; p < N; p++)
        for (int i = 0; i < N; i++)
            amount[p] += (graph[i][p] - graph[p][i]);
     
        minCashFlowRec(amount);
    }
     
    // Driver code
    public static void main (String[] args)
    {
        // graph[i][j] indicates the amount
        // that person i needs to pay person j
        int graph[][] = { {0, 1000, 2000},
                            {0, 0, 5000},
                            {0, 0, 0},};
     
        // Print the solution
        minCashFlow(graph);
    }
}
 
// This code is contributed by Anant Agarwal.


Python3
# Python3 program to fin maximum
# cash flow among a set of persons
 
# Number of persons(or vertices in graph)
N = 3
 
# A utility function that returns
# index of minimum value in arr[]
def getMin(arr):
     
    minInd = 0
    for i in range(1, N):
        if (arr[i] < arr[minInd]):
            minInd = i
    return minInd
 
# A utility function that returns
# index of maximum value in arr[]
def getMax(arr):
 
    maxInd = 0
    for i in range(1, N):
        if (arr[i] > arr[maxInd]):
            maxInd = i
    return maxInd
 
# A utility function to
# return minimum of 2 values
def minOf2(x, y):
 
    return x if x < y else y
 
# amount[p] indicates the net amount to
# be credited/debited to/from person 'p'
# If amount[p] is positive, then i'th
# person will amount[i]
# If amount[p] is negative, then i'th
# person will give -amount[i]
def minCashFlowRec(amount):
 
    # Find the indexes of minimum
    # and maximum values in amount[]
    # amount[mxCredit] indicates the maximum
    # amount to be given(or credited) to any person.
    # And amount[mxDebit] indicates the maximum amount
    # to be taken (or debited) from any person.
    # So if there is a positive value in amount[],
    # then there must be a negative value
    mxCredit = getMax(amount)
    mxDebit = getMin(amount)
 
    # If both amounts are 0,
    # then all amounts are settled
    if (amount[mxCredit] == 0 and amount[mxDebit] == 0):
        return 0
 
    # Find the minimum of two amounts
    min = minOf2(-amount[mxDebit], amount[mxCredit])
    amount[mxCredit] -=min
    amount[mxDebit] += min
 
    # If minimum is the maximum amount to be
    print("Person " , mxDebit , " pays " , min
        , " to " , "Person " , mxCredit)
 
    # Recur for the amount array. Note that
    # it is guaranteed that the recursion
    # would terminate as either amount[mxCredit]
    # or amount[mxDebit] becomes 0
    minCashFlowRec(amount)
 
# Given a set of persons as graph[] where
# graph[i][j] indicates the amount that
# person i needs to pay person j, this
# function finds and prints the minimum
# cash flow to settle all debts.
def minCashFlow(graph):
 
    # Create an array amount[],
    # initialize all value in it as 0.
    amount = [0 for i in range(N)]
 
    # Calculate the net amount to be paid
    # to person 'p', and stores it in amount[p].
    # The value of amount[p] can be calculated by
    # subtracting debts of 'p' from credits of 'p'
    for p in range(N):
        for i in range(N):
            amount[p] += (graph[i][p] - graph[p][i])
 
    minCashFlowRec(amount)
     
# Driver code
 
# graph[i][j] indicates the amount
# that person i needs to pay person j
graph = [ [0, 1000, 2000],
          [0, 0, 5000],
          [0, 0, 0] ]
 
minCashFlow(graph)
 
# This code is contributed by Anant Agarwal.


C#
// C# program to fin maximum cash
// flow among a set of persons
using System;
 
class GFG
{
    // Number of persons (or
    // vertices in the graph)
    static int N = 3;
     
    // A utility function that returns
    // index of minimum value in arr[]
    static int getMin(int []arr)
    {
        int minInd = 0;
        for (int i = 1; i < N; i++)
            if (arr[i] < arr[minInd])
                minInd = i;
        return minInd;
    }
     
    // A utility function that returns
    // index of maximum value in arr[]
    static int getMax(int []arr)
    {
        int maxInd = 0;
        for (int i = 1; i < N; i++)
            if (arr[i] > arr[maxInd])
                maxInd = i;
        return maxInd;
    }
     
    // A utility function to return
    // minimum of 2 values
    static int minOf2(int x, int y)
    {
        return (x < y) ? x: y;
    }
     
    // amount[p] indicates the net amount
    // to be credited/debited to/from person 'p'
    // If amount[p] is positive, then
    // i'th person will amount[i]
    // If amount[p] is negative, then
    // i'th person will give -amount[i]
    static void minCashFlowRec(int []amount)
    {
        // Find the indexes of minimum and
        // maximum values in amount[]
        // amount[mxCredit] indicates the maximum amount
        // to be given (or credited) to any person .
        // And amount[mxDebit] indicates the maximum amount
        // to be taken(or debited) from any person.
        // So if there is a positive value in amount[],
        // then there must be a negative value
        int mxCredit = getMax(amount), mxDebit = getMin(amount);
     
        // If both amounts are 0, then
        // all amounts are settled
        if (amount[mxCredit] == 0 &&
            amount[mxDebit] == 0)
            return;
     
        // Find the minimum of two amounts
        int min = minOf2(-amount[mxDebit], amount[mxCredit]);
        amount[mxCredit] -= min;
        amount[mxDebit] += min;
     
        // If minimum is the maximum amount to be
        Console.WriteLine("Person " + mxDebit +
                          " pays " + min + " to " +
                          "Person " + mxCredit);
     
        // Recur for the amount array.
        // Note that it is guaranteed that
        // the recursion would terminate
        // as either amount[mxCredit] or
        // amount[mxDebit] becomes 0
        minCashFlowRec(amount);
    }
     
    // Given a set of persons as graph[]
    // where graph[i][j] indicates
    // the amount that person i needs to
    // pay person j, this function
    // finds and prints the minimum
    // cash flow to settle all debts.
    static void minCashFlow(int [,]graph)
    {
        // Create an array amount[],
        // initialize all value in it as 0.
        int []amount=new int[N];
     
        // Calculate the net amount to
        // be paid to person 'p', and
        // stores it in amount[p]. The
        // value of amount[p] can be
        // calculated by subtracting
        // debts of 'p' from credits of 'p'
        for (int p = 0; p < N; p++)
        for (int i = 0; i < N; i++)
            amount[p] += (graph[i,p] - graph[p,i]);
     
        minCashFlowRec(amount);
    }
     
    // Driver code
    public static void Main ()
    {
        // graph[i][j] indicates the amount
        // that person i needs to pay person j
        int [,]graph = { {0, 1000, 2000},
                         {0, 0, 5000},
                         {0, 0, 0},};
     
        // Print the solution
        minCashFlow(graph);
    }
}
 
// This code is contributed by nitin mittal.


PHP
 $arr[$maxInd])
            $maxInd = $i;
    return $maxInd;
}
 
// A utility function to return minimum of 2 values
function minOf2($x, $y)
{
    return ($x < $y)? $x: $y;
}
 
// amount[p] indicates the net amount
// to be credited/debited to/from person 'p'
// If amount[p] is positive, then i'th
// person will amount[i]
// If amount[p] is negative, then i'th
// person will give -amount[i]
function minCashFlowRec($amount)
{
    // Find the indexes of minimum and
    // maximum values in amount[]
    // amount[mxCredit] indicates the
    // maximum amount to be given
    // (or credited) to any person .
    // And amount[mxDebit] indicates the
    // maximum amount to be taken
    // (or debited) from any person.
    // So if there is a positive value in
    // amount[], then there must
    // be a negative value
    $mxCredit = getMax($amount);
    $mxDebit = getMin($amount);
 
    // If both amounts are 0, then
    // all amounts are settled
    if ($amount[$mxCredit] == 0 &&
        $amount[$mxDebit] == 0)
        return;
 
    // Find the minimum of two amounts
    $min = minOf2(-$amount[$mxDebit], $amount[$mxCredit]);
    $amount[$mxCredit] -= $min;
    $amount[$mxDebit] += $min;
 
    // If minimum is the maximum amount to be
    echo "Person ".$mxDebit." pays ".$min." to Person ".$mxCredit."\n";
 
    // Recur for the amount array. Note
    // that it is guaranteed that the
    // recursion would terminate as
    // either amount[mxCredit]
    // or amount[mxDebit] becomes 0
    minCashFlowRec($amount);
}
 
// Given a set of persons as graph[]
// where graph[i][j] indicates the
// amount that person i needs to
// pay person j, this function finds
// and prints the minimum cash flow
// to settle all debts.
function minCashFlow($graph)
{
    global $N;
     
    // Create an array amount[],
    // initialize all value in it as 0.
    $amount=array_fill(0, $N, 0);
 
    // Calculate the net amount to be
    // paid to person 'p', and stores
    // it in amount[p]. The value of
    // amount[p] can be calculated by
    // subtracting debts of 'p' from
    // credits of 'p'
    for ($p = 0; $p < $N; $p++)
        for ($i = 0; $i < $N; $i++)
            $amount[$p] += ($graph[$i][$p] - $graph[$p][$i]);
 
    minCashFlowRec($amount);
}
 
    // Driver code
 
    // graph[i][j] indicates the amount
    // that person i needs to pay person j
    $graph = array(array(0, 1000, 2000),
                        array(0, 0, 5000),
                        array(0, 0, 0));
 
    // Print the solution
    minCashFlow($graph);
     
// This code is contributed by mits
?>


Javascript


输出:

Person 1 pays 4000 to Person 2
Person 0 pays 3000 to Person 2