zoukankan      html  css  js  c++  java
  • [USACO06FEB]稳定奶牛分配Steady Cow Assignment

    题目链接

    稳定奶牛分配

    题目描述

    农夫约翰有(N(1 le N le 1000))只奶牛,每只奶牛住在(B(1 le B le 20))个奶牛棚中的一个。当然,奶牛棚的容量有限。有些奶牛对它现在住的奶牛棚很满意,有些就不太满意了。
    农夫约翰想要重新安排这些奶牛,使得奶牛的满意度尽可能相同,尽管有可能这意味者所有的奶牛都不喜欢新分配的奶牛棚。
    每只奶牛都按顺序给出她喜欢的奶牛棚。在某个分配方案中,一只奶牛的满意度等于她对她的奶牛棚的评价等级。你的工作是找出一种分配方案使得没有奶牛棚超出它的容量,而且奶牛给分配到的奶牛棚的评价等级的相对范围(即分配到的等级最高的奶牛棚和等级最低的奶牛棚之间的差值)尽可能的小。

    输入格式

    第一行:两个用空格隔开的整数,(N)和B
    第二行到第(N+1)行:每一行都有(B)个用空格隔开的正整数,它们恰好是(1)(B)的一个排列。第(i+1)行的第一个整数是第(i)只奶牛的首选牛棚的编号,该行的第二个整数是第(i)只奶牛的第二选择,等等。
    (N+2)行:(B)个用空格隔开的整数,分别表示这(B)个奶牛棚的容量。这些数的和保证至少为(N)

    输出格式

    一个整数,被分配到的牛棚等级的最小相对差值。

    样例输入

    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
    

    样例输出

    2
    

    提示

    每个奶牛都被安排在它的第一选择或第二选择:(1)号牛棚安排(1)号奶牛和(5)号奶牛,(2)号牛棚安排(2)号奶牛,(3)号牛棚安排(4)号奶牛,(4)号牛棚安排(3)号奶牛和(6)号奶牛。

    题解

    要求求出把奶牛分别分配到牛棚后最小的满意度的差值。
    我们看到牛棚的个数很少,只有(20),所以我们可以暴力枚举答案,然后判断能否有安排方法满足条件。
    我们考虑把(s)到每个奶牛连一条流量为(1)的边,然后把所有牛棚到(t)连一条流量为这个牛棚容量的边。
    然后不可能把每个奶牛和牛棚都连边,要求所连所有边中最大的值减最小的值(满意度)要小于等于(ans)
    那么我们只要再根据(ans)枚举区间就好了,然后把满意度在区间内的边全部连上,然后跑一遍网络流。
    如果最大流等于牛的个数(也就是所有牛都能通过在限制范围内的边到牛棚里),那么这个方案就可行。
    当然你可以从小到大枚举(ans),也可以用二分来求(ans)(反正(B)只有20,差距不大)。

    但是你发现如果不加任何优化的话会有一个点跑不过去。
    我们首先用当前弧优化(这个不用说都会加上吧)。
    但还是跑不过去。
    我们考虑(s)到奶牛的流量只有(1),如果找到增广路之后就可以直接退到(s)了,所以我们判断如果当前最大值为(0)的话直接退出,不用再往下扫了。
    但是这还是过不去。
    我们再考虑如果扫完一个点之后,流量还有剩余(就是当前弧优化后到这个点的最大值减去流量之后不为(0)),那么就说明(s)到这个点有流量,但是这个点到(t)已经没有流量了,那么其他点就不能通过这个点到(t)有增广路了,也就是说接下来这个点不用再扫了,那么我们把这个点的(dis[])值设为(-1)就好了。
    加上这些优化就能过所有的点了。
    上代码:

    #include<bits/stdc++.h>
    #define inf 2000000000
    using namespace std;
    int n,b;
    int a[1009][29];
    int s[29];
    struct aa{
        int to,nxt,w;
    }p[50000];
    int h[2009],len;
    void add(int u,int v,int w){
        p[++len].to=v;
        p[len].nxt=h[u];
        p[len].w=w;
        h[u]=len;
        p[++len].to=u;
        p[len].nxt=h[v];
        p[len].w=0;
        h[v]=len;
    }
    int t;
    int uu[5009];
    int l,r;
    int dis[5009];
    bool bfs(){
        memset(dis,-1,sizeof(dis));
        dis[0]=0;
        uu[l=r=1]=0;
        while(l<=r){
            int u=uu[l++];
            for(int j=h[u];j;j=p[j].nxt){
                if(p[j].w && dis[p[j].to]==-1){
                    dis[p[j].to]=dis[u]+1;
                    uu[++r]=p[j].to;
                }
            }
        }
        return dis[t]!=-1;
    }
    int dfs(int u,int mx){
        if(u==t) return mx;
        int oo=0,xx;
        for(int j=h[u];j;j=p[j].nxt){
            if(dis[p[j].to]==dis[u]+1){
                xx=dfs(p[j].to,min(mx,p[j].w));
                oo+=xx;
                mx-=xx;
                p[j].w-=xx;
                p[j^1].w+=xx;
                if(mx==0) break;//最大值为$0$,直接退出
            }
        }
        if(mx!=0) dis[u]=-1;//当前点不用再被扫了
        return oo;
    }
    int dinic(){
        int ans=0;
        while(bfs()) ans+=dfs(0,inf);
        return ans;
    }
    int main(){
        scanf("%d%d",&n,&b);
        t=n+b+1;
        for(int j=1;j<=n;j++)
            for(int i=1;i<=b;i++)
                scanf("%d",&a[j][i]);
        for(int j=1;j<=b;j++)
            scanf("%d",&s[j]);
        for(int l=1;l<=b;l++){
            for(int j=1;j+l-1<=b;j++){
                memset(h,0,sizeof(h));
                len=1;
                for(int i=1;i<=n;i++)
                    add(0,i,1);
                for(int i=1;i<=b;i++)
                    add(n+i,t,s[i]);
                for(int o=1;o<=n;o++)
                    for(int oo=j;oo<=j+l-1;oo++)
                        add(o,n+a[o][oo],1);
                if(dinic()==n){
                    printf("%d",l);
                    return 0;
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    搜索回车跳转页面
    登录验证码
    【排序算法】排序算法之插入排序
    PAT 乙级 1044 火星数字 (20 分)
    PAT 甲级 1035 Password (20 分)
    PAT 甲级 1041 Be Unique (20 分)
    PAT 甲级 1054 The Dominant Color (20 分)
    PAT 甲级 1027 Colors in Mars (20 分)
    PAT 甲级 1083 List Grades (25 分)
    PAT 甲级 1005 Spell It Right (20 分)
  • 原文地址:https://www.cnblogs.com/linjiale/p/12026105.html
Copyright © 2011-2022 走看看