1027. 最优账单平衡(待完善)-dfs

发布时间 2023-11-30 17:34:29作者: 易先讯

题目描述

一群朋友在度假期间会相互借钱。比如说,小爱同学支付了小新同学的午餐共计 10 美元。如果小明同学支付了小爱同学的出租车钱共计 5 美元。我们可以用一个三元组 (x, y, z) 表示一次交易,表示 x 借给 y 共计 z 美元。用 0, 1, 2 表示小爱同学、小新同学和小明同学(0, 1, 2 为人的标号),上述交易可以表示为 [[0, 1, 10], [2, 0, 5]]。

给定一群人之间的交易信息列表,计算能够还清所有债务的最小次数。

注意:

一次交易会以三元组 (x, y, z) 表示,并有 x ≠ y 且 z > 0。
人的标号可能不是按顺序的,例如标号可能为 0, 1, 2 也可能为 0, 2, 6。

示例 1:

输入:
2
0 1 10
2 0 5

输出:
2

解释:
人 #0 给人 #1 共计 10 美元。
人 #2 给人 #0 共计 5 美元。

需要两次交易。一种方式是人 #1 分别给人 #0 和人 #2 各 5 美元。

示例 2:

输入:
4
0 1 10
1 0 1
1 2 5
2 0 5

输出:
1

解释:
人 #0 给人 #1 共计 10 美元。Person #0 gave person #1 $10.
人 #1 给人 #0 共计 1 美元。Person #1 gave person #0 $1.
人 #1 给人 #2 共计 5 美元。Person #1 gave person #2 $5.
人 #2 给人 #0 共计 5 美元。Person #2 gave person #0 $5.

因此,人 #1 需要给人 #0 共计 4 美元,所有的债务即可还清。

 

 

package main

import "fmt"

func main() {
    var n, x, y, z int
    m := make(map[int]int)
    fmt.Scan(&n)
    for n > 0 {
        fmt.Scan(&x, &y, &z)
        m[x] += z
        if m[x] == 0 {
            delete(m, x)
        }
        m[y] -= z
        if m[y] == 0 {
            delete(m, y)
        }
        n--
    }
    fmt.Println(len(m) - 1)
}

  

 

解答要求时间限制:1000ms, 内存限制:64MB
输入

第一行为三元组个数,之后每一行为一个三元组,三元组成员间以空格分隔

输出

输出能够还清所有债务的最小次数

样例

输入样例 1 复制

2
0 1 10
2 0 5

输出样例 1

2

 

 

分析:

刚开始所有人债务为0,然后每输入一行,更新2个人的总债务数,最后把总债务数为0的剔除,看还剩多少人。

代码:(40%用例通过)

 

分析:

我这里求出了一共有m个人的债务总数不为0,输出的是m-1

实际上应该进一步求出,这m个数,最多可以分为多少组,使得每一组的总和都为0,假设k组,输出m-k

对于有的用例k=1,但是有的用例k>1

如何求k,待完善。

 

 

package main

import "fmt"

func minTransfers(transactions [][]int) int {
	balances := make(map[int]int)
	for _, t := range transactions {
		balances[t[0]] -= t[2]
		balances[t[1]] += t[2]
	}
	debts := []int{}
	for _, v := range balances {
		if v != 0 {
			debts = append(debts, v)
		}
	}
	return settleDebts(debts, 0)
}

func settleDebts(debts []int, start int) int {
	for start < len(debts) && debts[start] == 0 {
		start++
	}
	if start == len(debts) {
		return 0
	}
	minTrans := int(^uint(0) >> 1)
	for i := start + 1; i < len(debts); i++ {
		if debts[i]*debts[start] < 0 {
			debts[i] += debts[start]
			minTrans = min(minTrans, 1+settleDebts(debts, start+1))
			debts[i] -= debts[start]
		}
	}
	return minTrans
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func main() {
	transactions := [][]int{{0, 1, 10}, {2, 0, 5}}
	fmt.Println(minTransfers(transactions))
}

  

 

 

 

package main

import "fmt"

var input [100]int
var result = int(^uint(0) >> 1)

/**
1.递归写法,每次递归返回后,需要清除上一步的操作;
2.for循环里面嵌套递归;
3.我的代码是预置了100人,人数这里还需要优化下。
*/

func main() {
	var len int
	fmt.Scan(&len)
	for len > 0 {
		var x, y, z int
		fmt.Scan(&x, &y, &z)
		input[y] += z
		input[x] -= z
		len--
	}
	res := dfs(0, 0)
	fmt.Print(res)
}

func dfs(start, num int) int {
	for start < 100 && input[start] == 0 {
		start++
	}
	if start == 100 {
		result = min(result, num)
	}
	for i := start + 1; i < 100; i++ {
		if (input[i] < 0 && input[start] > 0) || (input[i] > 0 && input[start] < 0) {
			input[i] += input[start]
			result = min(result, dfs(start+1, num+1))
			input[i] -= input[start]
		}
	}
	return result
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}