题意:有$n$个人,$m$个债务关系,$u_{i}$,$v_{i}$,$d_{i}$表示第$u_{i}个人$欠第$v_{i}$个人$d_{i}$块钱,现在你需要简化债务关系,使得债务总额最小。比如,$A$欠$B$十元,$B$欠$C$十五元,$C$欠$A$十元,此时总的债务为$10+15+10=35$,我们可以把债务关系简化为$B$欠$C$五元,那这样总的债务为$5$。
思路:其实每个人只关心自己借出或者借进了多少钱,所以求出每个人借出或者借进了多少钱,再将借进和借出的人分开,两两进行配对,确保每次配对总能消除一个人,比如求出$A$借出$6$元,$B$借进$2$元,$C$借进$4$元,第一次将$A$和$B$配对,消除$B$,此时相当于$A$只借出了$4$元,再将$A$与$C$配对消除$C$即可,因为每次配对都能消除一个人,所以求出来的债务总额也肯定最小。
#include <iostream> #include <algorithm> #include <cstdio> using namespace std; typedef long long ll; const int N = 300010; int n, m, rc, ru[N], rv[N]; int pu[N], pv[N], nu, nv; ll d[N], rw[N]; int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); d[u] += (ll)w, d[v] -= (ll)w; } for (int i = 1; i <= n; i++) { if (d[i] > 0) pu[++nu] = i; if (d[i] < 0) pv[++nv] = i; } int p1 = 1, p2 = 1; while (p1 <= nu && p2 <= nv) { if (d[pu[p1]] > abs(d[pv[p2]])) { rw[++rc]= abs(d[pv[p2]]); d[pu[p1]] -= abs(d[pv[p2]]); ru[rc] = pu[p1], rv[rc] = pv[p2]; p2++; } else if (d[pu[p1]] < abs(d[pv[p2]])) { rw[++rc] = d[pu[p1]]; d[pv[p2]] += d[pu[p1]]; ru[rc] = pu[p1], rv[rc] = pv[p2]; p1++; } else { rw[++rc] = d[pu[p1]]; d[pu[p1]] = d[pv[p2]] = 0; ru[rc] = pu[p1], rv[rc] = pv[p2]; p1++, p2++; } } printf("%d ", rc); for (int i = 1; i <= rc; i++) printf("%d %d %lld ", ru[i], rv[i], rw[i]); return 0; }