1. 程式人生 > >【BZOJ】2561: 最小生成樹【網路流】【最小割】

【BZOJ】2561: 最小生成樹【網路流】【最小割】

2561: 最小生成樹

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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;
  資料保證圖中沒有自環。
 

Output

 輸出一行一個整數表示最少需要刪掉的邊的數量。

Sample Input

3 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; }