Codeforces Global Round 6 - D. Decreasing Debts(思维)

题意:有$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\n", rc);
    for (int i = 1; i <= rc; i++) printf("%d %d %lld\n", ru[i], rv[i], rw[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zzzzzzy/p/12198192.html