zoukankan      html  css  js  c++  java
  • bzoj5251: [2018多省省队联测]劈配(网络流 + 二分)

    https://www.lydsy.com/JudgeOnline/problem.php?id=5251

    第一问:

    左边一列点代表学生,右边一列点代表导师

    导师向汇点连流量为 人数限制的 边

    然后从第一个学生的第一志愿往里面加边

    如果当前学生的当前志愿可以满足,即目前网络流可以满流,保留这一志愿的边,然后下一个学生

    否则,删除这一志愿的边,然后下一个志愿

    第二问:

    二分这个学生要前进多少名

    假设是学生i要前进x名

    把前i-x-1名的学生 在第一问中满足的志愿 的边加进去

    在把学生i的边加进去

    判断是否满流

    注意判断满流的时候 不包括前i-x-1名学生里没有任何导师的学生

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    #define N 201
    #define M 80801 
    
    int n,m;
    
    int lim[N];
    int a[N][N][N];
    int cnt[N][N];
    
    int dream[N];
    
    int tot=1;
    int src,decc;
    int lev[N<<1],cur[N<<1];
    int front[M<<1],nxt[M<<1],to[M<<1],cap[M<<1];
    queue<int>q;
    
    int st[N];
    
    inline void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    inline void init()
    {
        read(n); read(m);
        decc=n+m+1;
        for(int i=1;i<=m;++i) read(lim[i]);
        int x;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
            {
                read(x);
                if(x) a[i][x][++cnt[i][x]]=j;
            }
        for(int i=1;i<=n;++i) read(dream[i]);
    }
    
    inline void add(int u,int v,int w)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; cap[tot]=w;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; cap[tot]=0;
    }
    
    inline bool bfs()
    {
        for(int i=0;i<=decc;++i) cur[i]=front[i],lev[i]=-1;
        while(!q.empty()) q.pop();
        q.push(src);
        lev[src]=0;
        int now,t;
        while(!q.empty())
        {
            now=q.front();
            q.pop();
            for(int i=front[now];i;i=nxt[i])
            {
                t=to[i];
                if(lev[t]==-1 && cap[i])
                {
                    lev[t]=lev[now]+1;
                    if(t==decc) return true;
                    q.push(t);
                }
            }
        }
        return false;
    }
    
    inline int dinic(int now,int flow)
    {
        if(now==decc) return flow;
        int rest=0,delta;
        for(int &i=cur[now];i;i=nxt[i])
            if(cap[i] && lev[to[i]]==lev[now]+1)
            {
                delta=dinic(to[i],min(flow-rest,cap[i]));
                if(delta)
                {
                    rest+=delta; 
                    cap[i]-=delta; cap[i^1]+=delta;
                    if(rest==flow) break;
                }
            }
        if(rest!=flow) lev[now]=-1;
        return rest;
    }
    
    void solve1()
    {
        for(int i=1;i<=m;++i) add(n+i,decc,lim[i]);
        int ok;
        for(int i=1;i<=n;++i)
        {
            add(src,i,1);
            for(int j=1;j<=m;++j)
                if(cnt[i][j])
                {
                    for(int k=1;k<=cnt[i][j];++k) add(i,n+a[i][j][k],1);
                    if(bfs()) 
                    {
                        dinic(src,i);
                        st[i]=j;
                        break;
                    }
                    else
                    {
                        for(int k=1,h=tot;k<=cnt[i][j];++k,h-=2) cap[h]=cap[h-1]=0;
                    }
                }
        }
        for(int i=1;i<=n;++i) printf("%d ",st[i] ? st[i] : m+1);
        putchar('
    ');
    }
    
    inline bool check(int x,int goal)
    {
        tot=1;
        memset(front,0,sizeof(front));
        for(int i=1;i<=m;++i) add(n+i,decc,lim[i]);
        int ok=0;
        for(int i=1;i<goal;++i)
        {
            add(src,i,1);
            if(!st[i]) 
            {
                ok++;
                continue;
            }
            for(int j=1;j<=cnt[i][st[i]];++j) add(i,n+a[i][st[i]][j],1);
        }
        add(src,x,1);
        for(int i=1;i<=dream[x];++i)
            for(int j=1;j<=cnt[x][i];++j) add(x,n+a[x][i][j],1);
        while(bfs()) ok+=dinic(src,goal);
        return ok==goal;
    }
    
    void solve2()
    {
        int l,r,mid,ans;
        for(int i=1;i<=n;++i)
        {
            if(st[i] && st[i]<=dream[i])
            {
                printf("0 ");
                continue;
            }
            ans=i;
            l=1; r=i-1;
            while(l<=r)
            {
                mid=l+r>>1;
                if(check(i,i-mid)) ans=mid,r=mid-1;
                else l=mid+1;
            }
            printf("%d ",ans);
        }
        putchar('
    ');
    }
    
    void clear()
    {
        memset(st,0,sizeof(st));
        memset(cnt,0,sizeof(cnt));
        memset(front,0,sizeof(front));
        tot=1;
    }
    
    int main()
    {
        //freopen("mentor.in","r",stdin);
        //freopen("mentor.out","w",stdout);
        int T,C;
        read(T); read(C);
        while(T--)
        {
            clear();
            init();
            solve1();
            solve2();
        }
    }
  • 相关阅读:
    【Android Developers Training】 49. 轻松录制视频
    【Android Developers Training】 48. 轻松拍摄照片
    【Android Developers Training】 47. 序言:拍摄照片
    【Android Developers Training】 46. 处理音频外放设备
    【Android Developers Training】 45. 控制音频焦点
    【Android Developers Training】 44. 控制你应用的音量和播放
    【Android Developers Training】 43. 序言:管理音频播放
    【Android Developers Training】 42. 从另一台设备接收文件
    【Android Developers Training】 41. 向另一台设备发送文件
    Linux开发常见问题:GCC:链接器输入文件未使用,因为链接尚未完成
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8990640.html
Copyright © 2011-2022 走看看