[最大流][二分]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

 

posted @ 2019-07-05 07:37  Vagari  阅读(251)  评论(0编辑  收藏  举报