题意:
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;
}