• POJ3189二分最大流(枚举下界,二分宽度,最大流判断可行性)


    题意:
          有n头猪,m个猪圈,每个猪圈都有一定的容量(就是最多能装多少只猪),然后每只猪对每个猪圈的喜好度不同(就是所有猪圈在每个猪心中都有一个排名),然后要求所有的猪都进猪圈,但是要求所有的喜好度排名最低的和最高的差值的绝对值最小,输出这个最小的差值,就是是每个猪进猪圈后都会产生一个范围,就是最喜欢和最不喜欢(用排名的名次表示),然后把所有的范围放在一起,最小的端点个最大的端点的差的绝对值最小是多少?


    思路:
           做了将近两个小时才搞定,一直是超时,先说下我的做法,就是枚举下界,二分答案,然后DINIC判断是否可行,用G++交跑100+ms,用C++交超时,还有一个目测比较快的方法,就是把上面的DINIC换成多重匹配,多重匹配处理二分图的时候比DINIC快,所以理论上更优,可惜我没写过多重匹配,这个会的可以试试,最后我用匈牙利,然后暴力拆点去模拟多重匹配,超时了,呵呵,下面是我一开始最笨的方法,枚举下界+二分答案+DINIC判断可行性的代码,还有就是提醒下,输入的时候那个排名什么的要看清楚,就是读懂输入,嘿嘿别的没啥。




    用G++提交
    枚举起点,二分长度,最大流判断可行。
    #include<queue>
    #include<stdio.h>
    #include<string.h>


    #define N_node 1000 + 20 + 5
    #define N_edge (1000 * 20 + 1000 + 20) * 2 + 5000
    #define INF 1000000000


    using namespace std;


    typedef struct
    {
        int to ,cost ,next;
    }STAR;


    typedef struct
    {
        int x ,t;
    }DEP;


    STAR E[N_edge];
    DEP xin ,tou;
    int list[N_node] ,listt[N_node] ,tot;
    int deep[N_node];
    int Sort[1005][22];
    int Cow[22];
    int ANS ,N;




    void add(int a ,int b ,int c)
    {
        E[++tot].to = b;
        E[tot].cost = c;
        E[tot].next = list[a];
        list[a] = tot;


        E[++tot].to = a;
        E[tot].cost = 0;
        E[tot].next = list[b];
        list[b] = tot;
    }


    int minn(int x ,int y)
    {
        return x < y ? x : y;
    }


    bool BFS_Deep(int s ,int t ,int n)
    {
        memset(deep ,255 ,sizeof(deep));
        xin.x = s ,xin.t = 0;
        deep[xin.x] = xin.t;
        queue<DEP>q;
        q.push(xin);
        while(!q.empty())
        {
            tou = q.front();
            q.pop();
            for(int k = list[tou.x] ;k ;k = E[k].next)
            {
                xin.x = E[k].to;
                xin.t = tou.t + 1;
                if(deep[xin.x] != -1 || !E[k].cost)
                continue;
                deep[xin.x] = xin.t;
                q.push(xin);
            }
        }
        for(int i = 0 ;i <= n ;i ++)
        listt[i] = list[i];
        return deep[t] != -1;
    }


    int DFS_Flow(int s ,int t ,int flow)
    {
        if(s == t) return flow;
        int nowflow = 0;
        for(int k = listt[s] ;k ;k = E[k].next)
        {
            listt[s] = k;
            int to = E[k].to;
            int c = E[k].cost;
            if(deep[to] != deep[s] + 1 || !c)
            continue;
            int tmp = DFS_Flow(to ,t, minn(c ,flow - nowflow));
            nowflow += tmp;
            E[k].cost -= tmp;
            E[k^1].cost += tmp;
            if(flow == nowflow)
            break;
        }
        if(!nowflow) deep[s] = 0;
        return nowflow;
    }


    int DINIC(int s ,int t ,int n)
    {
        int Ans = 0;
        while(BFS_Deep(s ,t ,n))
        {
            Ans += DFS_Flow(s ,t ,INF);
            if(Ans == N) break;
        }
        return Ans;
    }


    void Buid(int n ,int m ,int a ,int b)
    {
        memset(list ,0 ,sizeof(list));
        tot = 1;
        for(int i = 1 ;i <= n ;i ++)
        add(0 ,i ,1);
        for(int i = 1 ;i <= m ;i ++)
        add(i + n ,m + n + 1 ,Cow[i]);
        for(int i = 1 ;i <= n ;i ++)
        for(int j = 1 ;j <= m ;j ++)
        if(Sort[i][j] >= a && Sort[i][j] <= b)
        add(i ,j + n ,1);
    }


    int solve(int n ,int m ,int ii)
    {
        int low = 0 ,up = m - ii ,mid ,Ans = INF;
        if(up > ANS) up = ANS;
        while(low <= up)
        {
            mid = (low + up) >> 1;
            Buid(n ,m ,ii ,ii + mid);
            if(DINIC(0 ,n + m + 1 ,n + m + 1) == n)
            {
                Ans = mid;
                up = mid - 1;
            }
            else low = mid + 1;
        }
        return Ans;
    }


    int main ()
    {
        int n ,m ,i ,j ,a;
        while(~scanf("%d %d" ,&n ,&m))
        {
            N = n;
            for(i = 1 ;i <= n ;i ++)
            for(j = 1 ;j <= m ;j ++)
            {
                scanf("%d" ,&a);
                Sort[i][a] = j;
            }
            for(i = 1 ;i <= m ;i ++)
            scanf("%d" ,&Cow[i]);
            ANS = INF;
            for(i = 1 ;i <= m ;i ++)
            {
                ANS = minn(ANS ,solve(n ,m ,i));
            }
            printf("%d " ,ANS + 1);
        }
        return 0;
    }







  • 相关阅读:
    【BZOJ 3282】Tree Link Cut Tree模板题
    【BZOJ 2002】【Hnoi 2010】弹飞绵羊 分块||Link Cut Tree 两种方法
    【BZOJ 1507】【NOI 2003】&【Tyvj P2388】Editor 块状链表模板题
    小结-Splay
    【BZOJ 3545】【ONTAK 2010】Peaks & 【BZOJ 3551】【ONTAK 2010】Peaks加强版 Kruskal重构树
    【BZOJ 3732】 Network Kruskal重构树+倍增LCA
    【BZOJ 3674】可持久化并查集加强版&【BZOJ 3673】可持久化并查集 by zky 用可持久化线段树破之
    【BZOJ 1901】【Zju 2112】 Dynamic Rankings 动态K值 树状数组套主席树模板题
    1020: [SHOI2008]安全的航线flight
    POJ
  • 原文地址:https://www.cnblogs.com/csnd/p/12062462.html
Copyright © 2020-2023  润新知