【BZOJ】2561: 最小生成树【网络流】【最小割】
2561: 最小生成树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2685 Solved: 1253
[Submit][Status][Discuss]
Description
给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上?
Input
第一行包含用空格隔开的两个整数,分别为N和M;
接下来M行,每行包含三个正整数u,v和w表示图G存在一条边权为w的边(u,v)。
最后一行包含用空格隔开的三个整数,分别为u,v,和 L;
数据保证图中没有自环。
接下来M行,每行包含三个正整数u,v和w表示图G存在一条边权为w的边(u,v)。
最后一行包含用空格隔开的三个整数,分别为u,v,和 L;
数据保证图中没有自环。
Output
输出一行一个整数表示最少需要删掉的边的数量。
Sample Input
3 2
3 2 1
1 2 3
1 2 2
3 2 1
1 2 3
1 2 2
Sample Output
1
HINT
对于20%的数据满足N ≤ 10,M ≤ 20,L ≤ 20;
对于50%的数据满足N ≤ 300,M ≤ 3000,L ≤ 200;
对于100%的数据满足N ≤ 20000,M ≤ 200000,L ≤ 20000。
Solution
完全看不出是网络流QAQ.....
很神奇的想法...
要使加的边在最小生成树上,就要使原图中所有能连接$u,v$的边并且长度小于$L$的通路被切断,最大生成树同理。
所以就是以$u,v$为源汇点跑最小割。重新建边。
为什么可以建双向边?因为这道题没确定方向,所以双向边是必要的。而在bfs中从源点出发更新其他点的$dep$,相当于是确定了方向,所以双向边也可以跑最小割了。
Code
#include<bits/stdc++.h> using namespace std; inline void read(int &x) { x = 0; char ch = getchar(); while(ch > '9' || ch < '0') ch = getchar(); while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } } struct Node { int u, v, f, nex; Node(int u = 0, int v = 0, int nex = 0, int f = 0) : u(u), v(v), nex(nex), f(f) { } } Edge[4000005]; struct Init { int u, v, w; } a[200005]; int stot = 1, h[20005]; void add(int u, int v, int f) { Edge[++stot] = Node(u, v, h[u], f); h[u] = stot; Edge[++stot] = Node(v, u, h[v], 0); h[v] = stot; } int n, m, s, t, w; int vis[20005], dep[20005]; bool bfs() { memset(vis, 0, sizeof(vis)); memset(dep, 0, sizeof(dep)); queue < int > q; q.push(s); vis[s] = 1; while(!q.empty()) { int u = q.front(); q.pop(); for(int i = h[u]; i; i = Edge[i].nex) { int v = Edge[i].v; if(!vis[v] && Edge[i].f) { dep[v] = dep[u] + 1; vis[v] = 1; q.push(v); } } } return vis[t]; } int dfs(int u, int delta) { if(u == t || !delta) return delta; int res = 0; for(int i = h[u]; i && delta; i = Edge[i].nex) { int v = Edge[i].v; if(dep[v] == dep[u] + 1 && Edge[i].f) { int dd = dfs(v, min(delta, Edge[i].f)); Edge[i].f -= dd; Edge[i ^ 1].f += dd; res += dd; delta -= dd; } } return res; } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= m; i ++) read(a[i].u), read(a[i].v), read(a[i].w); read(s), read(t), read(w); for(int i = 1; i <= m; i ++) if(a[i].w < w) add(a[i].u, a[i].v, 1), add(a[i].v, a[i].u, 1); int t1 = 0, t2 = 0; while(bfs()) t1 += dfs(s, 0x3f3f3f3f); stot = 1; memset(h, 0, sizeof(h)); for(int i = 1; i <= m; i ++) if(a[i].w > w) add(a[i].u, a[i].v, 1), add(a[i].v, a[i].u, 1); while(bfs()) t2 += dfs(s, 0x3f3f3f3f); printf("%d", t1 + t2); return 0; }