zoukankan      html  css  js  c++  java
  • BZOJ 2229 / Luogu P3329 [ZJOI2011]最小割 (分治最小割板题)

    题面

    求所有点对的最小割中<=c的数量

    分析

    分治最小割板题

    首先,注意这样一个事实:如果(X,Y)是某个s1-t1最小割,(Z,W)是某个s2-t2最小割,那么X∩Z、X∩W、Y∩Z、Y∩W这四项不可能均非空。也就是说,最小割不可能相互跨立。

    这个蕴含了,最多一共有N-1个不同的s-t最小割。只需把这些割找出来即可。

    寻找的方法:首先,在V中任意找两个点a,b,求最大流,把V划分为割X-Y,之后对X、Y分别递归地进行划分。这样就能得到N-1个割了。
    (摘自hzwer的博客)

    CODE

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    char cb[1<<15],*cs=cb,*ct=cb;
    #define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
    template<typename T>inline void read(T &num) {
        char ch; int flg=1;
        while((ch=getc())<'0'||ch>'9')if(ch=='-')flg=-flg;
        for(num=0;ch>='0'&&ch<='9';num=num*10+ch-'0',ch=getc());
        num*=flg;
    }
    const int inf = 1e9;
    const int MAXN = 155;
    const int MAXM = 100005;
    int n, m, Q, fir[MAXN], S, T, cnt;
    struct edge { int to, nxt, c; }e[MAXM];
    inline void add(int u, int v, int cc) { //双向边
        e[cnt] = (edge){ v, fir[u], cc }; fir[u] = cnt++;
        e[cnt] = (edge){ u, fir[v], cc }; fir[v] = cnt++;
    }
    int dis[MAXN], vis[MAXN], info[MAXN], cur, q[MAXN];
    inline bool bfs() {
        int head = 0, tail = 0;
        vis[S] = ++cur; q[tail++] = S; dis[S] = 0;
        while(head < tail) {
            int u = q[head++];
            for(int i = fir[u]; ~i; i = e[i].nxt)
                if(e[i].c && vis[e[i].to] != cur)
                    vis[e[i].to] = cur, dis[e[i].to] = dis[u] + 1, q[tail++] = e[i].to;
        }
        if(vis[T] == cur) memcpy(info, fir, (n+1)<<2);
        return vis[T] == cur;
    }
    int dfs(int u, int Max) {
        if(u == T || !Max) return Max;
        int flow=0, delta;
        for(int i = fir[u]; ~i; i = e[i].nxt)
            if(e[i].c && dis[e[i].to] == dis[u] + 1 && (delta=dfs(e[i].to, min(e[i].c, Max-flow)))) {
                e[i].c -= delta, e[i^1].c += delta, flow += delta;
                if(flow == Max) return flow;
            }
    	if(!flow) dis[u] = -1;
        return flow;
    }
    inline int dinic() {
        int flow=0, x;
        while(bfs()) while((x=dfs(S, inf))) flow+=x;
        return flow;
    }
    inline void clear() {
    	for(int i = 0; i < cnt; i+=2)
    		e[i].c = e[i^1].c = (e[i].c + e[i^1].c) >> 1;
    }
    int now; bool mark[MAXN];
    void cut(int u) {
    	mark[u] = 1;
    	for(int i = fir[u]; ~i; i = e[i].nxt)
    		if(e[i].c && !mark[e[i].to]) cut(e[i].to);
    }
    int a[MAXN], tmp[MAXN], ans[MAXN][MAXN];
    void solve(int l, int r) {
    	if(l == r) return; clear();
    	S = a[l], T = a[r]; int MinCut = dinic();
    	memset(mark, 0, sizeof mark); cut(S);
    	for(int i = 1; i <= n; ++i) if(mark[i])
    		for(int j = 1; j <= n; ++j) if(!mark[j])
    			ans[i][j] = ans[j][i] = min(ans[i][j], MinCut);
    	int L = l, R = r;
    	for(int i = l; i <= r; ++i)
    		if(mark[a[i]]) tmp[L++] = a[i];
    		else tmp[R--] = a[i];
    	for(int i = l; i <= r; ++i) a[i] = tmp[i];
    	solve(l, L-1), solve(R+1, r);
    }
    int arr[12000], top;
    int main () {
    	int kase, x;
    	read(kase);
    	while(kase--) {
    		memset(fir, -1, sizeof fir); cnt = 0;
    		memset(ans, 0x7f, sizeof ans);
    		read(n), read(m);
    		for(int i = 1, x, y, z; i <= m; ++i)
    			read(x), read(y), read(z), add(x, y, z);
    		for(int i = 1; i <= n; ++i) a[i] = i;
    		solve(1, n);
    		top = 0;
    		for(int i = 1; i <= n; ++i)
    			for(int j = i+1; j <= n; ++j)
    				arr[top++] = ans[i][j];
    		sort(arr, arr+top);
    		read(Q);
    		while(Q--)
    			read(x), printf("%d
    ", upper_bound(arr, arr+top, x)-arr);
    		puts("");
    	}
    }
    
  • 相关阅读:
    算法---递归及尾递归
    ScheduledThreadPoolExecutor之remove方法
    数据结构---队列及简单实现有界队列
    数据结构---栈及四则运算实现
    数据结构---链表及约瑟夫环问题带来的思考
    数据结构---数组
    时间复杂度和空间复杂度
    Redis缓存设计与性能优化
    Springboot+ELK实现日志系统简单搭建
    Docker学习笔记(三):Dockerfile及多步骤构建镜像
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039406.html
Copyright © 2011-2022 走看看