• [POJ3189][cqbzoj1640]稳定的奶牛分配 解题报告


    [POJ3189]稳定的奶牛分配

    时间限制: 1 Sec 内存限制: 64 MB

    题目描述

    农夫约翰有N(1<=N<=1000)只奶牛,每只奶牛住在B(1<=B<=20)个奶牛棚中的一个。当然,奶牛棚的容量有限。有些奶牛对它现在住的奶牛棚很满意,有些就不太满意了。

    农夫约翰想要重新安排这些奶牛,使得奶牛的满意度尽可能相同,尽管有可能这意味者所有的奶牛都不喜欢新分配的奶牛棚。

    每只奶牛都按顺序给出她喜欢的奶牛棚。在某个分配方案中,一只奶牛的满意度等于她对她的奶牛棚的评价等级。你的工作是找出一种分配方案使得没有奶牛棚超出它的容量,而且奶牛给分配到的奶牛棚的评价等级的范围(即分配到的等级最高的奶牛棚和等级最低的奶牛棚之间的差值+1)尽可能的小。

    附上原文:the size of the range (i.e., one more than the positive difference between the the highest-ranked barn chosen and that lowest-ranked barn chosen) of barn rankings the cows give their assigned barns is as small as possible.

    输入

    第1行:两个用空格隔开的整数,N和B
    第2..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.枚举答案上界u与下界d(就是奶牛的满意度上界和下界)
    2.按照u和d建图
    建图方法:
    - 1.每个奶牛和每个牛棚代表一个节点
    - 2.源点向每头奶牛连边,边权为1 代表这头奶牛只能使用一次
    - 3.每头奶牛向这头奶牛选择中满意度在[u,d]之间的牛棚连一条权值为1的边
    4.每个牛棚向汇点连一条权值为牛棚容量的边
    3.跑最大流
    4.判断flow是否等于奶牛数量 如果相等,ans=min(ans,d-u+1);

    如果把枚举换成二分答案建图跑得飞快
    但是原谅我太懒提供不了二分版本答案(. V . )

    接下来是代码

    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    namespace isap{
    const int MAXN=2000;
    const int MAXM=1000000;
    const int INF=0x7f7f7f7f;
    const int INF4BIT=0x7f;
    struct Node{
        int v,c,nxt,bk;
    }nodes[MAXM];
    int head[MAXN],e_total;
    int n,S,T;
    inline void addedge(int a,int b,int c){
        e_total++;
        nodes[e_total].v=b;
        nodes[e_total].c=c;
        nodes[e_total].nxt=head[a];
        nodes[e_total].bk=e_total+1;
        head[a]=e_total;
        e_total++;
        nodes[e_total].v=a;
        nodes[e_total].c=0;
        nodes[e_total].nxt=head[b];
        nodes[e_total].bk=e_total-1;
        head[b]=e_total;
    }
    bool vis[MAXN];
    int d[MAXN],vd[MAXN];
    void spfa(int start){
        queue<int>que;
        que.push(start);
        vis[start]=true;
        while(!que.empty()){
            int u=que.front();
            que.pop();
            vis[u]=false;
            for(int e=head[u];e;e=nodes[e].nxt)
                if(d[nodes[e].v]>d[u]+1){
                    d[nodes[e].v]=d[u]+1;
                    if(!vis[nodes[e].v]){
                        vis[nodes[e].v]=true;
                        que.push(nodes[e].v);
                    }
                }
        }
        for(int i=1;i<=n;i++)
            if(d[i]<=n)vd[d[i]]++;
    }
    int aug(int u,int augv){
        if(u==T)return augv;
        int last=augv;
        for(int e=head[u];e;e=nodes[e].nxt)
            if(nodes[e].c&&d[nodes[e].v]+1==d[u]){
                int t=aug(nodes[e].v,min(nodes[e].c,last));
                nodes[e].c-=t;
                nodes[nodes[e].bk].c+=t;
                last-=t;
                if(d[S]>=n||!last)return augv-last;
            }
        if(augv==last){
            vd[d[u]]--;
            if(!vd[d[u]]){d[S]=n+1;return 0;}
            d[u]=n+1;
            for(int e=head[u];e;e=nodes[e].nxt)
                if(nodes[e].c)d[u]=min(d[u],d[nodes[e].v]+1);
            vd[d[u]]++;
        }
        return augv-last;
    }
    int sap(){
        for(int i=1;i<=n;i++)
            d[i]=INF;
        d[T]=0;
        spfa(T);
        int flow=0;
        while(d[S]<n)flow+=aug(S,INF);
        return flow;
    }
    void clear(){
        memset(nodes,0,sizeof nodes);
        memset(vis,0,sizeof vis);
        memset(head,0,sizeof head);
        e_total=0;
        memset(vd,0,sizeof vd);
    }
    }
    int n,m;
    int inp[1200][30];
    int bns[30];
    void build(int l,int r){
        isap::S=1;
        isap::T=isap::S+n+m+1;
        isap::n=isap::T;
        for(int i=1;i<=n;i++){
            isap::addedge(isap::S,isap::S+i,1);
            for(int j=l;j<=r;j++)
                isap::addedge(isap::S+i,isap::S+n+inp[i][j],1);
        }
        for(int i=1;i<=m;i++)
            isap::addedge(isap::S+n+i,isap::T,bns[i]);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&inp[i][j]);
        for(int i=1;i<=m;i++)
            scanf("%d",&bns[i]);
        int ans=m;
        for(int i=1;i<=m;i++)
            for(int j=i;j<=m;j++){
                if(j-i+1>=ans)continue;
                isap::clear();
                build(i,j);
                int t=isap::sap();
                if(t>=n)ans=min(j-i+1,ans);
            }
        printf("%d
    ",ans);
    }
  • 相关阅读:
    Linux运维笔记
    回到顶部过渡js代码
    好想你红枣
    鼠标点击区域问题
    ie6 hover 子元素无效bug
    IE6和7下text-indent导致inline-block标签消失的bug
    星星评分js代码
    洛谷P3147 [USACO16OPEN]262144 2048 合并 倍增 动归 递推
    洛谷P1114 “非常男女”计划
    洛谷P1108 低价购买 动态规划
  • 原文地址:https://www.cnblogs.com/Hineven/p/5843567.html
Copyright © 2020-2023  润新知