• 八省联考2018 劈配(网络流)


    碰到这种匹配的题

    二分图匹配,网络流嘛

    需要将选手按照排名从大倒小依次匹配,每个选手都是在上一个选手的残留网络上继续匹配

    为了满足当前选手的最优匹配,需要从小到大按顺序枚举选手的志愿进行匹配

    这样暴力建图匹配复杂度有点高,所以考虑二分,发现前i个志愿中有可以被录取的的,那更多的志愿一定可以被录取,是满足二分性的

    这样可以找到一个人的最优志愿匹配,第一问ok

    对于第二问,我们发现当一个人在一个排名可以满足期望值的时候,排名更靠前时一定更能满足

    那么就可以二分,求出满足期望值要增加最少的排名

    两次二分的建图方法是这样的

    源点向学员连容量为1的边,导师向汇点连容量为战队人数限制容量的边,学员和其选择的导师间连容量为1的边

    跑dinic,如果有流量,就表示能够匹配到

    首先将这个人之前(第一问就是编号这个排名,第二问要用编号排名减去上升的名次)的人的最优录取志愿中的导师加到图当中,这样保证之前的人匹配到的志愿依旧是满足前几个人的最优匹配的

    因为每个志愿选择的导师不会超过C个(C<=10),可以保证建图的复杂度

    (这个地方刚开始我是将所有志愿全都加进去,后来发现是不对的,并不能保证是最优的),然后跑一遍dinic,在残余网络上进行这个人的匹配

    这个人进行匹配时,第一问要将二分的志愿之前的所有志愿加到图中,第二问要将这个人最低期望录取志愿之前的所有志愿加到图中,跑一遍dinic

    可以发现,这样一共会跑O(nlogn)次dinic,时间复杂度是可以接受的

    注意点:我是用二维的vector存储每个人每个志愿想要选择的导师的,每组数据之前一定要保证完全清空(每组数据的最后将vector清空),否则会出问题的,因为这个debug了好久

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 2010;
    const int INF = 1e9+7;
    
    int T,C,n,m,s,t;
    int b[maxn],a[maxn][maxn],S[maxn];
    int res1[maxn],res2[maxn];
    
    vector<int> v[maxn][maxn];
    
    int h[maxn],size=1;
    struct E{
        int to,next,cap;
    }e[maxn<<10];
    void add(int u,int v,int c){
        e[++size].to=v;
        e[size].next=h[u];
        e[size].cap=c;
        h[u]=size;
    }
    
    int d[maxn];
    queue<int> q;
    int bfs(){
        memset(d,0,sizeof(d));
        while(!q.empty()) q.pop();
        d[s]=1; q.push(s);
        while(!q.empty()){
            int u=q.front(); q.pop();
            for(int i=h[u];i!=-1;i=e[i].next){
                int v=e[i].to;
                if(!d[v]&&e[i].cap){
                    d[v]=d[u]+1;
                    q.push(v);
                }
            }
        }
        return d[t];
    }
    
    int dfs(int u,int lim){
        if(u==t) return lim;
        int f=0,tmp;
        for(int i=h[u];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(d[v]==d[u]+1&&e[i].cap&&(tmp=dfs(v,min(lim,e[i].cap)))){
                e[i].cap-=tmp,e[i^1].cap+=tmp;
                f+=tmp,lim-=tmp;
                if(!lim) return f;
            }
        }
        if(lim) d[u]=0;
        return f;
    }
    
    int dinic(){
        int ans=0;
        while(bfs()){
            ans+=dfs(s,INF);
        }
        return ans;
    }
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f;}
    
    int main(){
        T=read(),C=read();
        while(T--){
            memset(h,-1,sizeof(h));
            n=read(),m=read();
            s=0,t=n+m+1;
            for(int i=1;i<=m;i++) b[i]=read();
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    a[i][j]=read();
                    v[i][a[i][j]].push_back(j);
                }
            }
            
            for(int i=1;i<=n;i++) S[i]=read();
            
            for(int i=1;i<=m;i++){
                add(i+n,t,b[i]),add(t,i+n,0);
            }
            
            for(int i=1;i<=n;i++){
                int l=1,r=m; int res=m+1;
                while(l<=r){
                    int mid=(l+r)/2;
                    memset(h,-1,sizeof(h)); size=1;
                    for(int j=1;j<i;j++) add(s,j,1),add(j,s,0); 
                    for(int j=1;j<i;j++){ 
                        int now=res1[j]; 
                        for(int k=0;k<v[j][now].size();k++){
                            add(j,v[j][now][k]+n,1),add(v[j][now][k]+n,j,0);
                        }
                    }
                    for(int j=1;j<=m;j++){ add(j+n,t,b[j]),add(t,j+n,0); }
                
                    dinic();
                    
                    add(s,i,1),add(i,s,0);
                    for(int j=1;j<=mid;j++){
                        for(int k=0;k<v[i][j].size();k++){
                            add(i,v[i][j][k]+n,1),add(v[i][j][k]+n,i,1);
                        }
                    }
                    
                    if(dinic()){
                        res=mid;
                        r=mid-1;
                    }else{
                        l=mid+1;
                    }
                }
                res1[i]=res;
            }
            
            for(int i=1;i<=n;i++) printf("%d ",res1[i]); printf("\n");
            
            for(int i=1;i<=n;i++){
                if(res1[i]>S[i]){
                    int l=1,r=i-1; int res=i;
                    while(l<=r){
                        int mid=(l+r)/2;
                        memset(h,-1,sizeof(h)); size=1;
                        
                        for(int j=1;j<i-mid;j++) add(s,j,1),add(j,s,0);
                        for(int p=1;p<i-mid;p++){
                            int now=res1[p];
                            for(int k=0;k<v[p][now].size();k++){
                                add(p,v[p][now][k]+n,1),add(v[p][now][k]+n,p,0);
                            }
                        }
                        for(int j=1;j<=m;j++){ add(j+n,t,b[j]),add(t,j+n,0); }
                        dinic();
    
                        add(s,i,1),add(i,s,0);
                        for(int j=1;j<=S[i];j++){
                            for(int k=0;k<v[i][j].size();k++){
                                add(i,v[i][j][k]+n,1),add(v[i][j][k]+n,i,0);
                            }
                        }
                        
                        if(dinic()){
                            res=mid;
                            r=mid-1;
                        }else{
                            l=mid+1;
                        }
                    }
                    res2[i]=res;
                }else{
                    res2[i]=0;
                }
            }
            for(int i=1;i<=n;i++) printf("%d ",res2[i]); printf("\n");
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    v[i][j].clear();
                }
            }
        }
    
        return 0;
    }
  • 相关阅读:
    CF280C Game on Tree 概率与期望
    bzoj 3420: Poi2013 Triumphal arch 树形dp+二分
    bzoj 2111: [ZJOI2010]Perm 排列计数 Lucas
    bzoj 3709: [PA2014]Bohater 贪心
    bzoj 1396/2865: 识别子串 后缀自动机+线段树
    【教程】如何搭建一个自己的网站
    C#单例设计模式
    C#双缓冲代码
    Hibernate的查询功能
    hibernate事务规范写法
  • 原文地址:https://www.cnblogs.com/tuchen/p/10567124.html
Copyright © 2020-2023  润新知