• 【题解】Ples [COCI2011]


    【题解】Ples [COCI2011]

    依旧是没有传送门,只有提供了数据官网

    【题目描述】

    (N) 个汉子和 (N) 个妹纸一起参加舞会,跳舞时只能是一个汉子一个妹纸配对,现在给出每个人的身高,任意一个人都只想和比 ( ext{ta}) 高(矮)的人跳,身高一样的人都不想与对方跳。输出满足人们愿望的前提下可组成的最多对数。.

    【输入】

    第一行一个数 (N) 表示汉子和妹纸的个数。

    第二行 (N) 个整数,其绝对值表示 (N) 个汉子的身高 (h)(h) 为正数表示他想与比自己高的人跳,负数则相反。

    第三行 (N) 个整数,表示妹纸,其它与第二行相同。

    【输出】

    一个数,表示组成的最多对数。.

    【样例】

    样例输入:
    1
    -1800
    1800
    
    样例输出:
    0
    
    样例输入:
    1
    1700
    -1800
    
    样例输出:
    1
    
    样例输入:
    2
    -1800 -2200
    1900 1700
    
    样例输出:
    2
    

    【数据范围】

    (100 \%:) (1 leqslant N leqslant 100000,) (1500 leqslant h[i] leqslant 2500)


    【分析】

    乍一看:我 (c),开局就上送分板子题。

    恩恩?不对不对,光是建图就要体验 (n) 方卡百万。

    再一看:([1500,2500]) 迅速发现了隐藏数据范围 (h leqslant 1000),反手就是一个网络流

    这应该是 ( ext{COCI2011}) 写起来最爽的一道题了吧。。。不过正解貌似是贪心。

    由于本题只关注相对大小,可以把输入的每个 (h) 都减去 (1500) 再加 (1),映射到 ([1,1001]) 里面去,然后记录在每一种身高下汉子、妹纸的个数。

    (A[h][1]) 表示高度为 (h)想要配偶比自己高的汉子数量,
    (A[h][0]) 表示高度为 (h)想要配偶比自己矮的汉子数量;
    (B[h][1]) 表示高度为 (h)想要配偶比自己高的妹纸数量,
    (B[h][0]) 表示高度为 (h)想要配偶比自己矮的妹纸数量。

    对每个高度建四个点,分别表示上述加黑字体的四种人,超源连向所有汉子,妹纸连向所有超汇,容量设为人种数量。

    (1001^2) 枚举所有高度配对:

    对于 (h_i>h_j)(0) 汉子与 (1) 妹纸连一条容量为 (min(A[h_i][0],B[h_j][1])) 的边。

    对于 (h_i<h_j)(1) 汉子与 (0) 妹纸连一条容量为 (min(A[h_i][1],B[h_j][0])) 的边。

    然后随便背个最大流板子就 (ok) 啦。

    建边数量为:((1001^2+1001*4)*2=1006005*2)


    【Code】

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #define Re register int
    using namespace std;
    const int N=4050,M=1006050,inf=2e9;
    int n,x,o=1,T,st,ed,maxflow,A[N>>2][2],B[N>>2][2],head[N];
    struct QAQ{int to,next,flow;}a[M<<1];
    inline void add_(Re x,Re y,Re flow){a[++o].flow=flow,a[o].to=y,a[o].next=head[x],head[x]=o;}
    inline void add(Re x,Re y,Re flow){add_(x,y,flow),add_(y,x,0);}
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    int h,t,Q[N],cur[N],dis[N];
    inline int bfs(Re st,Re ed){
        for(Re i=0;i<=ed;++i)cur[i]=head[i],dis[i]=0;
        h=1,t=0,dis[st]=1,Q[++t]=st;
        while(h<=t){
            Re x=Q[h++],to;
            for(Re i=head[x];i;i=a[i].next)
                if(a[i].flow&&!dis[to=a[i].to]){
                    dis[to]=dis[x]+1,Q[++t]=to;
                    if(to==ed)return 1;
                }
        }
        return 0;
    }
    inline int dfs(Re x,Re flow){
        if(!flow||x==ed)return flow;
        Re tmp=0,to,f;
        for(Re i=cur[x];i;i=a[i].next){
            cur[x]=i;
            if(dis[to=a[i].to]==dis[x]+1&&(f=dfs(to,min(flow-tmp,a[i].flow)))){
                a[i].flow-=f,a[i^1].flow+=f,tmp+=f;
                if(tmp==flow)break;
            }
        }
        return tmp;
    }
    inline void Dinic(Re st,Re ed){while(bfs(st,ed))maxflow+=dfs(st,inf);}
    int main(){
    //  freopen("ples.in","r",stdin);
    //  freopen("ples.out","w",stdout);
        in(T),n=1001,st=n<<2|1,ed=st+1;
        for(Re i=1;i<=T;++i){
        	in(x);
        	if(x>0)++A[x-1500+1][1];//汉子想要妹纸比自己高
        	else ++A[-x-1500+1][0];//汉子想要妹纸比自己矮
        }
        for(Re i=1;i<=T;++i){
        	in(x);
        	if(x>0)++B[x-1500+1][1];//妹纸想要汉子比自己高
        	else ++B[-x-1500+1][0];//妹纸想要汉子比自己矮
        }
        for(Re i=1;i<=n;++i){//超源连汉子
        	if(A[i][0])add(st,i,A[i][0]);
        	if(A[i][1])add(st,i+n,A[i][1]);
        }
        for(Re i=1;i<=n;++i){//妹纸连超汇
        	if(B[i][0])add(i+(n<<1),ed,B[i][0]);
        	if(B[i][1])add(i+(n<<1)+n,ed,B[i][1]);
        }
        for(Re i=1;i<=n;++i){//汉子连妹纸
            if(A[i][0])
                for(Re j=1;j<i;++j)
                    if(B[j][1])add(i,j+(n<<1)+n,min(A[i][0],B[j][1]));//必须要两厢情愿才连边
            if(A[i][1])
                for(Re j=i+1;j<=n;++j)
                    if(B[j][0])add(i+n,j+(n<<1),min(A[i][1],B[j][0]));
        }
        Dinic(st,ed);
        printf("%d
    ",maxflow);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    
  • 相关阅读:
    3.1C#中的命名空间
    2章总结
    2.4冒泡排序
    2.3 C#中的数组
    2.2二重循环
    2.1c#中的循环语句
    1章总结
    docker内外数据拷贝
    搭建docker环境
    centos7 部署Apache的httpd服务器
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/11688262.html
Copyright © 2020-2023  润新知