gym-101667E How Many to Be Happy
How Many to Be Happy?
最小割
因为是最小生成树,因此可以考虑对于一条边来说,他的左右两端的点视为处于两个不同的集合,然后只通过该边进行连接,这样最小生成树就必然会利用这条边
比该边大的边显然不用考虑,就考虑比该边边权小的边,然后进行最小割,边流量为 \(1\)(分割成两个集合,且割的边数最少)
#include <iostream>
#include <cstdio>
#include <vector>
#include <array>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn = 2e4 + 10;
const int inf = 1e8;
int head[maxn], nexx[maxn], to[maxn], vol[maxn], vp = 1;
int dep[maxn], cur[maxn], n, m, s, t;
inline void add(int u, int v, int t)
{
vp++;
nexx[vp] = head[u];
to[vp] = v;
vol[vp] = t;
head[u] = vp;
}
bool bfs()
{
queue<int>q;
q.push(s);
for(int i=0; i<=n; i++) cur[i] = head[i];
for(int i=0; i<=n; i++) dep[i] = 0;
dep[s] = 1;
while(q.size())
{
int now = q.front();
q.pop();
for(int i=head[now]; i; i=nexx[i])
{
int nex = to[i];
if(dep[nex] == 0 && vol[i] > 0)
{
dep[nex] = dep[now] + 1;
q.push(nex);
}
}
}
return dep[t];
}
int dfs(int now, int flow = inf)
{
if(now == t) return flow;
int ans = 0;
for(int i=head[now]; i && flow; i=nexx[i])
{
int nex = to[i];
if(dep[nex] == dep[now] + 1 && vol[i])
{
int f = dfs(nex, min(flow, vol[i]));
vol[i] -= f;
vol[i ^ 1] += f;
ans += f;
flow -= f;
}
}
return ans;
}
int dinic()
{
int ans = 0;
while(bfs())
ans += dfs(s);
return ans;
}
int main()
{
cin >> n >> m;
vector<array<int, 3> >num(m);
for(int i=0; i<m; i++)
{
int a, b, c;
cin >> a >> b >> c;
num[i] = {c, a, b};
}
sort(num.begin(), num.end());
ll ans = 0;
for(auto [c, a, b] : num)
{
for(int i=0; i<=n; i++) head[i] = 0;
vp = 1;
for(auto [cc, aa, bb] : num)
{
if(cc >= c) break;
add(aa, bb, 1);
add(bb, aa, 0);
add(bb, aa, 1);
add(aa, bb, 0);
}
s = a;
t = b;
ans += dinic();
}
cout << ans << endl;
return 0;
}