题目链接
题意:给一个连通无向图,对于图中的每条边,这条边可能在某一颗最小生成树上,如果在称为happy的边,否则称为unhappy的边。对于unhappy的边,总是可以删掉一些边使得它变成happy的边,设h(e)为使e变成happy最少需要删的边数,定义happy边的h值为0,让你求所有边的h值之和。
题解:我们知道要是一个边没有在最小生成树里面,能对他造成影响的只有边权比它小的边(在构成最小生成树的过程中就是优先选边权小的边),所以我们在考虑要让这条边到最小生成树里面,就应该使比它边权小的边不连通,这样要是想选比它边权小的就必定要选它了,所以我们枚举每条边,让边权比它小的边连成一个图,起点和终点就是这条边的两个端点,现在要计算删除最少的边让这个图不连通,这就是最小割了。
PS:这里有个小疑问,为什么在建图的过程中反向边也要有流,望大佬提醒。
#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
#include <unordered_set>
const int mod = 998244353;
const int maxn = 5e5 + 5;
const int inf = 1e9;
const long long onf = 1e18;
#define me(a, b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI 3.14159265358979323846
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int n, m;
int head[maxn], cur[maxn], tot;
int depth[maxn];
int st, ed;
struct Node {
int u, v, val;
} a[maxn];
struct node {
int v, next, flow;
} tree[maxn];
void add_edge(int u, int v, int flow) {
tree[tot] = node{v, head[u], flow};
head[u] = tot++;
}
void ins(int u, int v, int flow) {
add_edge(u, v, flow);
add_edge(v, u, flow);
}
bool bfs() {
for (int i = 1; i <= n; i++)
depth[i] = -1;
depth[st] = 1;
queue<int> q;
q.push(st);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = head[u]; i != -1; i = tree[i].next) {
int v = tree[i].v, flow = tree[i].flow;
if (flow && depth[v] == -1) {
depth[v] = depth[u] + 1;
q.push(v);
}
}
}
return depth[ed] != -1;
}
int dfs(int u, int flow) {
if (u == ed)
return flow;
int used = 0;
for (int i = cur[u]; i != -1; i = tree[i].next) {
int v = tree[i].v, tempflow = tree[i].flow;
if (flow && depth[v] == depth[u] + 1) {
int Min = dfs(v, min(flow, tempflow));
if (Min) {
flow -= Min, used += Min;
tree[i].flow -= Min;
tree[i ^ 1].flow += Min;
}
}
}
return used;
}
int Dinic() {
int sum = 0;
while (bfs()) {
for (int i = 1; i <= n; i++)
cur[i] = head[i];
sum += dfs(st, inf);
}
return sum;
}
void init() {
for (int i = 1; i <= n; i++)
head[i] = -1;
tot = 0;
}
void work() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
scanf("%d%d%d", &a[i].u, &a[i].v, &a[i].val);
int ans = 0;
for (int i = 1; i <= m; i++) {
init();
for (int j = 1; j <= m; j++) {
if (a[j].val < a[i].val)
ins(a[j].u, a[j].v, 1);
}
st = a[i].u, ed = a[i].v;
ans += Dinic();
}
printf("%d\n", ans);
}
int main() {
#ifndef ONLINE_JUDGE
//freopen("1.in", "r", stdin);
#endif
int t = 1, Case = 1;
// cin >> t;
while (t--) {
// printf("Case %d: ", Case++);
work();
}
return 0;
}