📜  最小化一组给定的互相借钱的朋友之间的现金流

📅  最后修改于: 2021-10-25 11:30:13             🧑  作者: Mango

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

现金周转

以上债务可按以下优化方式清偿

现金周转

这个想法是使用贪婪算法,在每一步,结算一个人的所有数量,并对剩余的 n-1 个人重复。
如何选择第一人称?要选择第一个人,计算每个人的净金额,其中通过从所有贷项(要支付的金额)中减去所有债务(要支付的金额)来获得净金额。评估每个人的净金额后,找出净金额最大和最小的两个人。这两个人是最多的债权人和债务人。最少有两个的人是我们第一个被解决并从名单中删除的人。设两个数量中的最小值为 x。我们从最大债务人到最大债权人支付 ‘x’ 金额并结算一个人。如果 x 等于最大借方,则最大债务人被清偿,否则最大债权人被清偿。
下面是详细的算法。
对每个人 Pi 执行以下操作,其中 i 从 0 到 n-1。

  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

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程