题目大意
给你一堆债务关系,债务关系之间可以转移,让你简化债务关系,以使得债务关系中的债务之和最小。
解题思路
本来以为必须是本来就存在债务关系的一个集合之间才能互相转移,没想到没关系的也能转移。
比如说这组数据:
- 4 2
- 1 2 12
- 3 4 8
就可以转化为:
- 3 2 8
- 1 2 4
- 1 4 8
好了,现在你读懂题了,应该可以A了吧债务关系的总值之所以能过减少,是因为之前有人借来了某些钱又借了出去,等于说借出去的这波钱倒了好几手,我们对于每个人都统计他借来的钱和借出去的钱,把他们相减就能去掉这些倒来的钱,之后再配对就行了。配对的时候只要保持每个人有借贷关系的人都至少能匹配上一个人并且自己的债务不变就行了。
代码
const int maxn = 2e5+10;
const int maxm = 2e5+10;
int n, m;
ll d[maxn];
struct I {
int x, y; ll w;
};
int main() {
cin >> n >> m;
for (int i = 1, a, b, c; i<=m; ++i) {
scanf("%d%d%d", &a, &b, &c);
d[a] += c, d[b] -= c;
}
queue<Pll> a, b;
for (int i = 1; i<=n; ++i) {
if (d[i]>0) a.push({d[i], i});
else if (d[i]<0) b.push({d[i], i});
}
vector<I> ans;
while(!a.empty()) {
Pll t1 = a.front(); a.pop();
Pll t2 = b.front(); b.pop();
ll z = min(t1.x, abs(t2.x));
t1.x -= z;
t2.x += z;
if (t1.x) a.push(t1);
if (t2.x) b.push(t2);
ans.push_back({t1.y, t2.y, z});
}
cout << ans.size() << endl;
for (int i = 0; i<ans.size(); ++i) printf("%d %d %lld
", ans[i].x, ans[i].y, ans[i].w);
return 0;
}