Codeforces1266 D. Decreasing Debts(思维)

题意:

d(a,b)表示a欠b的钱,显然d关系可以构造成有向图
定义有向图的权值为图中的边权和.
为了减少图的权值,有一些债务时可以合并的:
1.假如存在d(a,b),d(c,d),其中a!=c,b!=d.
如果存在一个z<d(a,b),且z<d(c,d),
那么可以将d(a,b)和d(c,d)都减少z,
同时将d(c,b),d(a,d)加上z,
显然这样是合法的,因为只是转移了一下欠债人.
2.如果存在d(a,a)>0,那么可以令d(a,a)=0,
d(a,a)>0表示有收益,可以从债务图中约掉.

在进行操作之后,图的最小权值是多少,输出最后的图。

给定n和m,表示有n个人,一开始有m条带权有向边.

数据范围:n<=1e5,m<=3e5

解法:
只需要考虑每个人欠了多少钱和收到多少钱.
收入和支出抵消一下,最后会有若干个欠缺的人和收钱的人.
随意匹配一下就行了.

ps:
这题太思维了,朝图论方向胡乱分析了半天,根本搞不动.
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=2e6+5;
struct Node{
    int a,b,c;
};
int d[maxm];
int n,m;
signed main(){
    ios::sync_with_stdio(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int a,b,c;cin>>a>>b>>c;
        d[a]-=c,d[b]+=c;
    }
    stack<int>aa,bb;
    for(int i=1;i<=n;i++){
        if(d[i]<0){
            aa.push(i);
        }else if(d[i]>0){
            bb.push(i);
        }
    }
    vector<Node>ans;
    while(!aa.empty()){
        int x=aa.top();aa.pop();
        int y=bb.top();bb.pop();
        int t=min(-d[x],d[y]);
        d[x]+=t,d[y]-=t;
        if(d[x])aa.push(x);
        if(d[y])bb.push(y);
        ans.push_back({x,y,t});
    }
    cout<<ans.size()<<endl;
    for(auto i:ans){
        cout<<i.a<<' '<<i.b<<' '<<i.c<<endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值