给定一些朋友,他们必须互相给予或收取一定数量的钱。设计一种算法,使所有朋友之间的总现金流量最小化。
例子:
下图显示了要清偿的输入债务。
以上债务可按以下优化方式清偿
这个想法是使用贪婪算法,在每一步,结算一个人的所有数量,并对剩余的 n-1 个人重复。
如何选择第一人称?要选择第一个人,计算每个人的净金额,其中通过从所有贷项(要支付的金额)中减去所有债务(要支付的金额)来获得净金额。评估每个人的净金额后,找出净金额最大和最小的两个人。这两个人是最多的债权人和债务人。最少有两个的人是我们第一个被解决并从名单中删除的人。设两个数量中的最小值为 x。我们从最大债务人到最大债权人支付 ‘x’ 金额并结算一个人。如果 x 等于最大借方,则最大债务人被清偿,否则最大债权人被清偿。
下面是详细的算法。
对每个人 Pi 执行以下操作,其中 i 从 0 到 n-1。
- 计算每个人的净金额。可以通过从所有信用的总和中减去所有债务的总和来计算个人“i”的净金额。
- 找出最大债权人和最大债务人两个人。让最大债权人的最大贷记金额为 maxCredit,从最大债务人处借记的最大金额为 maxDebit。设最大债务人为 Pd,最大债权人为 Pc。
- 找出 maxDebit 和 maxCredit 的最小值。设两个的最小值为 x。从 Pd 借记“x”并将此金额记入 Pc
- 如果 x 等于 maxCredit,则从一组人中移除 Pc 并对剩余的 (n-1) 个人重复。
- 如果 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 现场工作专业课程和学生竞争性编程现场课程。