• [bzoj1305][CQOI2009]dance跳舞


    一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首或更多舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?

    n<=50,k<=30

    题解:很明显可以二分答案,然后用网络流来check(老套路)。建边问题,我们把每个男孩和女孩拆成它自己和不喜欢两个点,假设二分的答案是x,那么从S向男孩连x的边,从女孩向T连x的边。之后,从每个男孩向它的不喜欢的点连k的边,从每个女孩的不喜欢的点向她连k的边。最后处理男女孩关系,如果相互喜欢,那么两人连边;如果不喜欢,那么两人的不喜欢的点连边,边权都是1.

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define S 0
    #define T 201
    #define INF 2000000000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int cnt,head[T+5],c[T+5],q[T+5],d[T+5],n,k,top;
    struct edge{int to,next,w;}e[T*T*2+5];
    char st[55][55];
    
    void ins(int f,int t,int w)
    {
        e[++cnt]=(edge){t,head[f],w};head[f]=cnt;
        e[++cnt]=(edge){f,head[t],0};head[t]=cnt;
    }
    
    int dfs(int x,int f)
    {
        if(x==T)return f;
        int used=0;
        for(int&i=c[x];i;i=e[i].next)
            if(e[i].w&&d[e[i].to]==d[x]+1)
            {
                int w=dfs(e[i].to,min(f-used,e[i].w));
                used+=w;e[i].w-=w;e[i^1].w+=w;
                if(used==f)return used;
            }
        return d[x]=-1,used;
    }
    
    bool bfs()
    {
        memset(d,0,sizeof(d));int i,j;
        for(d[q[top=i=1]=S]=1;i<=top;i++)
            for(j=c[q[i]]=head[q[i]];j;j=e[j].next)
                if(e[j].w&&!d[e[j].to])
                    d[q[++top]=e[j].to]=d[q[i]]+1;
        return d[T];
    }
    
    void build(int x)
    {
        cnt=1;memset(head,0,sizeof(head));
        for(int i=1;i<=n;i++)
        {
            ins(S,i,x);ins(i+2*n,T,x);
            ins(i,i+n,k);ins(i+3*n,i+2*n,k);
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(st[i][j]=='Y')
                    ins(i,j+2*n,1);
                else
                    ins(i+n,j+3*n,1);
    }
    
    int main()
    {
        n=read();k=read();
        for(int i=1;i<=n;i++)
            scanf("%s",st[i]+1);
        int l=1,r=n,mid,ans=0;
        while(l<=r)
        {
            mid=l+r>>1;build(mid);
            int sum=0;
            while(bfs())sum+=dfs(S,INF);
            if(sum==mid*n)ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    (转)Android系统自带样式(@android:style/)
    Android:安卓资源引用符号的含义
    Android:再按一次退出程序
    Android:实现退出确认对话框
    Android:仿微信开场切换界面
    Android:ViewPager适配器PagerAdapter的使用
    Android:使用ViewPager实现左右滑动切换图片(图上有点点)
    Android:使用ViewPager实现左右滑动切换图片 (简单版)
    inflate方法与findViewById的区别
    Android:自定义标题栏
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj1305.html
Copyright © 2020-2023  润新知