BZOJ 2229 [Zjoi2011]最小割
来源:互联网 发布:python anaconda 安装 编辑:程序博客网 时间:2024/05/29 11:06
最小割树
关于最小割树的详细内容和证明,请看【ZJOI2016 day2讲课 无向图最小割】,这个东西自己找吧,我就不发了。。。
默默摘抄一些Gusfield算法
fa[u]在u被枚举到之前表示u所属点集的代表点,枚举到之后表示u在最小割树上的父亲。初始时所有点都属于以1为代表点的点集。从2到|V|依次枚举u,把u所在点集以u和fa[u]为源和汇拆分,所有被分到u侧的点x把fa[x]修改为u。
注意枚举之后只能把fa[x]=u或fa[x]=fa[u]的x拿来改,即属于当前点集的拿来改。这是小细节,不然会挂很惨。。。
关于跑完一次最大流之后如何确定最小割:找出从S开始在残量网络上BFS到的点和没被BFS到的点,这两个点集之间就是最小割
#include<cstdio>#include<cstring>#include<algorithm>#define N 155#define M 3005using namespace std;namespace runzhe2000{ const int INF = 1<<29; int n, m, ecnt = 1, last[N], cur[N], level[N], fa[N], fa_v[N], S, T, qx[N], arr[N*2], cnt[N*2]; struct edge{int next, to, flow;}e[M<<2]; void addedge(int a, int b, int c) { e[++ecnt] = (edge){last[a], b, c}; last[a] = ecnt; e[++ecnt] = (edge){last[b], a, 0}; last[b] = ecnt; } void linkedge(int a, int b, int c) { e[++ecnt] = (edge){last[a], b, c}; last[a] = ecnt; e[++ecnt] = (edge){last[b], a, c}; last[b] = ecnt; } int q[N], timer, vis[N]; bool bfs() { level[q[0] = S] = 1; vis[S] = ++timer; for(int head=0, tail=1; head<tail; head++) { int x = q[head]; for(int i = last[x]; i; i = e[i].next) { int y = e[i].to; if(vis[y] == timer || !e[i].flow) continue; vis[y] = timer; level[y] = level[x] + 1; if(y == T)return true; q[tail++] = y; } } return false; } int dfs(int x, int flow) { if(x == T)return flow; int use = 0; for(int &i = cur[x]; i; i = e[i].next) { int y = e[i].to; if(level[y] != level[x] + 1)continue; int w = dfs(y, min(e[i].flow, flow - use)); use += w; e[i].flow -= w; e[i^1].flow += w; if(use == flow)return use; } return use; } int dinic() { int ret = 0; while(bfs()) { memcpy(cur, last, sizeof(last)); ret += dfs(S, INF); } return ret; } void restore() { for(int i = 2; i <= ecnt; i += 2) e[i].flow += e[i^1].flow, e[i^1].flow = 0; } void dfs(int x, int v, int f) { cnt[v]++; for(int i = last[x]; i; i = e[i].next) { int y = e[i].to; if(y == f)continue; dfs(y, min(v, e[i].flow), x); } } void init() { ecnt = 1; memset(last,0,sizeof(last)); memset(cnt,0,sizeof(cnt)); } void main() { int kase; scanf("%d",&kase); for(; kase--; ) { init(); scanf("%d%d",&n,&m); for(int i = 1, a, b, c; i <= m; i++) { scanf("%d%d%d",&a,&b,&c); addedge(a,b,c); addedge(b,a,c); } for(int i = 1; i <= n; i++) fa[i] = 1; for(int i = 2; i <= n; i++) { restore(); S = i; T = fa[i]; fa_v[i] = dinic(); for(int j = i+1; j <= n; j++) if(vis[j] == timer && fa[j] == fa[i]) fa[j] = i; } int Q, tot = 0; scanf("%d",&Q); for(int i = 1; i <= Q; i++) scanf("%d",&qx[i]), arr[++tot] = qx[i]; for(int i = 2; i <= n; i++) arr[++tot] = fa_v[i]; sort(arr+1,arr+1+tot); tot = unique(arr+1,arr+1+tot) - arr - 1; for(int i = 1; i <= Q; i++) qx[i] = lower_bound(arr+1,arr+1+tot,qx[i]) - arr; for(int i = 2; i <= n; i++) fa_v[i] = lower_bound(arr+1,arr+1+tot,fa_v[i]) - arr; memset(last,0,sizeof(last)); ecnt = 1; for(int i = 2; i <= n; i++) linkedge(fa[i], i, fa_v[i]); for(int i = 1; i <= n; i++) dfs(i, N*2-1, 0); for(int i = 1; i < N*2; i++) { cnt[i] /= 2; cnt[i] += cnt[i-1]; } for(int i = 1; i <= Q; i++) printf("%d\n",cnt[qx[i]]); puts(""); } }}int main(){ runzhe2000::main();}
0 0
- bzoj 2229: [Zjoi2011]最小割
- BZOJ 2229:[Zjoi2011]最小割
- BZOJ 2229: [Zjoi2011]最小割
- BZOJ 2229 [Zjoi2011]最小割
- BZOJ 2229 [Zjoi2011] 最小割
- 【bzoj 2229 & luogu 3329】 [ZJOI2011]最小割
- 2229: [Zjoi2011]最小割
- BZOJ 2521: [Shoi2010]最小生成树&&2229: [Zjoi2011]最小割
- bzoj 2229: [Zjoi2011]最小割 分治最小割(最小割树)
- BZOJ 2229: [Zjoi2011]最小割 最小割树 / 分治最小割
- bzoj 2229: [Zjoi2011]最小割 分治&网络流
- 2229: [Zjoi2011]最小割 最小割
- BZOJ 2229 ZJOI2011 最小割 最小割+分治 400AC达成&&2000Submission达成
- 【ZJOI2011】【BZOJ2229】最小割
- P3329 [ZJOI2011]最小割
- bzoj2229: [Zjoi2011]最小割
- Bzoj2229:[Zjoi2011]最小割:分治最小割
- ZJOI2011最小割 最小割树
- Linux快速配置集群ssh互信
- 使用地图的API获取目标的经纬度以及获取两地间的距离
- 获取easyui-datagrid中文本列的值的正确方法
- Linux网络编程08——多播
- C++中获取一个原生数据类型能表示的最大值
- BZOJ 2229 [Zjoi2011]最小割
- sscanf的高级使用
- mysql 海量数据 优化 步骤!
- 变量 variable
- POJ 1442 Black Box
- 微信公众平台之模板消息
- 九度 oj 题目1482:玛雅人的密码
- Toggle && ToggleGroup
- 【Leetcode】476. Number Complement