2019ICPC EC-FINAL E-Flow 贪心
2019ICPC EC-FINAL E-Flow
题意
给一个\(n\)个点\(m\)条边的图,图由若干条从\(1\)到\(n\)的长度相同的独立路径构成,任意两条路径除了\(1\)号点和\(n\)号点没有公用的点,每条边有流量,每次操作可以使一条边的流量减一,另一条边的流量加一,问最少需要多少此操作可以使从\(1\)到\(n\)的流量最大。
\(n\le 10^5,m \le 2\cdot 10^5\)
分析
因为每条路径的长度相同,若长度为\(x\),则最大流量为\(\frac{\sum flow}{x}\)。
每条路径的流量的瓶颈是流量最小的那条边,将每条路径上的边权排序,一定是将流量大的边的转给流量小的边,
排序后,从小到大枚举所有路径上的第\(i\)条边作为瓶颈,若所有路径上第\(i\)条边的流量和小于最大流量,则通过后面的边可以转移过来和最大流量的差值,若已经大于等于最大流量了,后面的边一定都不是瓶颈了,算法结束。
Code
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
const int N=1e5+10;
const int inf=1e9+10;
int n,m;
int vis[N];
typedef pair<int,int> pii;
typedef long long ll;
vector<int>q;
vector<pii>g[N];
vector<vector<int> >v;
void dfs(int u){
for(pii x:g[u]){
q.push_back(x.se);
dfs(x.fi);
}
}
int main()
{
scanf("%d%d",&n,&m);
ll ans=0,sum=0;
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
g[x].push_back(pii(y,z));
sum+=z;
}
for(pii x:g[1]){
q.clear();
q.push_back(x.se);
dfs(x.fi);
sort(q.begin(), q.end());
v.push_back(q);
}
sum/=q.size();
for(int i=0;i<q.size();i++){
ll tmp=0;
for(auto x:v){
tmp+=x[i];
}
if(tmp>=sum) break;
ans+=sum-tmp;
}
printf("%lld\n",ans);
return 0;
}