题意:
n个点,m条边,从点1到点n有k条相同长度的路径,每个边都有对应的容量,你可以进行任意次操作,每次将一个边的容量-1,将另一个边的容量+1,问最少操作多少次可以使得跑最大流的结果最大
题解:
很容易发现我们可以直接计算出最大流的最大值,因为我们有所有边的容量,极端操作我们可以将所有边的容量全部分配到一条路上,也就是最大流的最大值
s
u
m
=
所
有
流
量
综
合
一
条
路
径
的
长
度
sum=\frac{所有流量综合}{一条路径的长度}
sum=一条路径的长度所有流量综合
如果我们不操作,当前的最大流答案为每条路径的最小值之和,不过当前这个最大流的答案要比理想的sum小,我们如何通过操作提升到sum?
刚才分析得出,最大流的结果和每一条路径的最小值有关,那我们就每次操作提升最小值即可。我们将每一条道路上的边按照容量排序(每条路之间彼此独立,没有影响),然后每一条路径的最小容量之和,就是当前最大流sum1,sum减sum1就是我们要补的量(也就是操作次数),补完后我们开始考虑每一条路径的次小值,之和sum2就是当前最新的网络流,与sum的差距就是再次要补的量。这样一直操作,直到最新的网络流容量大于等于sum
你可能要问我们知道被补的,那谁是被扣除的呢?其实不用管,因为我们已经求了sum,也就是总有操作可以使得最大流到sum,我们每次补可以认为是容量大的一些边均摊减,我们不需要知道具体的操作方案,只需要知道操作的影响和结果即可
代码:
#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{
x= 0;
char c= getchar();
bool flag= 0;
while (c < '0' || c > '9')
flag|= (c == '-'), c= getchar();
while (c >= '0' && c <= '9')
x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();
if (flag)
x= -x;
read(Ar...);
}
template <typename T> inline void write(T x)
{
if (x < 0) {
x= ~(x - 1);
putchar('-');
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
startTime = clock ();
freopen("data.in", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
endTime= clock();
printf("\nRun Time:%lfs\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn=2e5+9;
vector<pair<int,ll> >vec[maxn];
vector<ll>v[maxn];
ll ans=0;
int main()
{
//rd_test();
int n,m;
read(n,m);
ll tot=0;
for(int i=1;i<=m;i++){
int x,y,w;
read(x,y,w);
vec[x].push_back({y,w});
tot+=w;
}
int cnt=0;
for(int i=0;i<vec[1].size();i++){
cnt++;
int tmp=vec[1][i].first;
v[cnt].push_back(vec[1][i].second);
while(tmp!=n){
v[cnt].push_back(vec[tmp][0].second);
tmp=vec[tmp][0].first;
}
}
for(int i=1;i<=cnt;i++){
sort(v[i].begin(),v[i].end());
}
ll k=m/cnt;
ll ave=tot/k;
for(int i=0;i<k;i++){
ll sum=0;
for(int j=1;j<=cnt;j++)sum+=v[j][i];
ans+=max(0ll,ave-sum);
}
cout<<ans<<endl;
//Time_test();
}