• [最大流][二分]JZOJ 1259 牛棚


    Description

    Farmer John的N(1<=N<=1000)头奶牛分别居住在农场所拥有的B(1<=B<=20)个牛棚的某一个里。有些奶牛很喜欢她们当前住的牛棚,而另一些则讨厌再在它们现在所在的牛棚呆下去。
    FJ在忍受了若干次奶牛的抱怨后,决定为所有奶牛重新安排牛棚,使最不满的那头奶牛与最高兴的奶牛的心情差异最小,即使这会让所有奶牛都更加郁闷。
    每头奶牛都把她对各个牛棚的好感度从高到低排序后告诉了FJ。当然,如果一头奶牛被安排到的牛棚在她给出的列表中越靠后,她就会越郁闷。你可以认为奶牛的郁闷指数是她被分配到的牛棚在列表中的位置。奶牛们是斤斤计较的,她们无法容忍别的奶牛在自己喜欢的牛棚里快乐地生活,而自己却呆在一个自己不喜欢的牛棚里。每个牛棚都只能容纳一定数量的奶牛。FJ希望在每个牛棚都没有超出容量限制的前提下,使最郁闷和最高兴的奶牛的郁闷指数的跨度最小。 
    FJ请你帮他写个程序,来计算这个最小的郁闷指数跨度到底是多少。
     

    Input

    第1行: 包含2个用空格隔开的整数N和B,分别表示牛和牛棚的数量
    第2..N+1行: 每行包含B个用空格隔开的整数,刚好完全包含1..B的整数。第i+1行的第一个整数,表示奶牛i最喜欢的牛棚编号。第二个整数表示奶牛i的列表中排在第二位,也就是她第二喜欢的牛棚。依此类推。
    第N+2行: 包含B个用空格隔开的整数,第i个整数表示牛棚i最多能容纳的奶牛的数目。所有牛棚能容纳奶牛头数的和至少是N。 

    Output

    第1行: 输出一个整数,表示所有奶牛中最高兴与最郁闷的牛的郁闷指数跨度
     

    Sample Input

    6 4
    1 2 3 4
    2 3 1 4
    4 2 3 1
    3 1 2 4
    1 3 4 2
    1 4 2 3
    2 1 3 2
    

    Sample Output

    2
     

    Data Constraint

     
     

    Hint

    【样例说明】
    每头奶牛都能被安排进她的第一或第二喜欢的牛棚。下面给出一种合理的分配方案:奶牛1和奶牛5住入牛棚1,牛棚2由奶牛2独占,奶牛4住进牛棚3,剩下的奶牛3和奶牛6安排到牛棚4。

    分析

    发现牛棚对于奶牛有唯一对应关系,但每个牛棚有连接限制

    不难想到网络流,以喜欢度作为权值

    我们可以二分这个答案,然后枚举权值区间的左端l,则区间为[l,l+mid)

    做最大流的时候加这个限制就好了

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <memory.h>
    using namespace std;
    const int N=1e3+10;
    const int B=21;
    struct Pipe {
        int u,v,c,w,nx;
    }g[2*N*B+2*N+2*B];
    int cnt=1,list[N+B],p[B],dis[N+B];
    int n,b;
    int s,t,mid,ans,l;
    
    void Add(int u,int v,int w,int c) {
        g[++cnt]=(Pipe){u,v,c,w,list[u]};list[u]=cnt;
        g[++cnt]=(Pipe){v,u,0,0,list[v]};list[v]=cnt;
    }
    
    bool Spfa(int v0) {
        queue<int> q;
        while (!q.empty()) q.pop();
        memset(dis,0,sizeof dis);
        q.push(v0);dis[v0]=1;
        while (!q.empty()) {
            int u=q.front();q.pop();
            for (int i=list[u];i;i=g[i].nx)
                if (!dis[g[i].v]&&g[i].c&&(l<=g[i].w&&g[i].w<=l+mid-1||g[i].w==0)) {
                    dis[g[i].v]=dis[u]+1;
                    if (g[i].v==t) return 1;
                    q.push(g[i].v);
                }
        }
        return 0;
    }
    
    int DFS(int u,int mf) {
        int flow,ret=0;
        if (u==t||mf==0) return mf;
        for (int i=list[u];i;i=g[i].nx)
            if (dis[u]+1==dis[g[i].v]&&(l<=g[i].w&&g[i].w<=l+mid-1||g[i].w==0)) {
                flow=DFS(g[i].v,min(g[i].c,mf));
                g[i].c-=flow;g[i^1].c+=flow;
                ret+=flow;
                if (ret==mf) return ret;
            }
        return ret;
    }
    
    bool MCF() {
        int flow;
        for (l=1;l<=max(1,b-mid+1);l++) {
            flow=0;
            while (Spfa(s))
                flow+=DFS(s,2147483647);
            for (int i=2;i<=cnt;i+=2)
                if (g[i].u==s) g[i].c=p[g[i].v],g[i^1].c=0;
                else g[i].c=1,g[i^1].c=0;
            if (flow==n) return 1;
        }
    }
    
    int main() {
        scanf("%d%d",&n,&b);
        s=0;t=n+b+1;
        for (int i=1;i<=n;i++)
            for (int j=1,c;j<=b;j++) {
                scanf("%d",&c);
                Add(c,i+b,j,1);
            }
        for (int i=1;i<=b;i++) scanf("%d",&p[i]),Add(s,i,0,p[i]);
        for (int i=1;i<=n;i++) Add(i+b,t,0,1);
        int l=1,r=20;
        while (l<=r) {
            mid=l+r>>1;
            if (MCF()) ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%d",ans);
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    http 请求包含哪几个部分(请求行、请求头、请求体)
    BUG处理流程说明
    如何正确分析定位BUG
    如何定位bug是前端还是后端以及用的工具
    测试阶段划分为哪几个阶段?
    java实现一个简单的图书管理系统
    sql增、删、改、查基础封装类
    Ubuntu18.04 install sougou pinyin
    tensorboard网页打不开问题
    c++11 实现numpy argmax argmin
  • 原文地址:https://www.cnblogs.com/mastervan/p/11136082.html
Copyright © 2020-2023  润新知