bzoj千题计划130:bzoj1305: [CQOI2009]dance跳舞

http://www.lydsy.com/JudgeOnline/problem.php?id=1305

 

每个人拆为喜欢(yes)和不喜欢(no)两个点

二分答案

1、每两个人之间只能跳一次

喜欢则 男yes i 向 女yes j 连流量为1的边

不喜欢则 男no i 向 女no j 连流量为1的边

2、最多与k个不喜欢的人跳

男yes i 向 男no i 连流量为 k的边

女no j 向 女yes j 连流量为k 的边

3、

源点向 男yes i 连流量mid 的边

女yes j 向汇点连流量为mid的边

 

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

#define N 2501
#define M 3001

int n,k;
char s[51];
bool mp[51][51];

int tot;
int front[N],to[M<<1],nxt[M<<1],val[M<<1];

int src,decc;

int cur[N],lev[N];

queue<int>q;

void read(int &x)
{
    x=0;  char c=getchar();
    while(!isdigit(c)) c=getchar(); 
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar();  }
}

void add(int u,int v,int w)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=0;
}

void rebuild(int mid)
{
    tot=1;
    memset(front,0,sizeof(front));
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
            if(mp[i][j]) add(i,n*3+j,1);
            else add(n+i,n*2+j,1);
    for(int i=1;i<=n;++i) add(src,i,mid);
    for(int i=1;i<=n;++i) add(n*3+i,decc,mid);
    for(int i=1;i<=n;++i) add(i,n+i,k);
    for(int i=1;i<=n;++i) add(n*2+i,n*3+i,k);
}

bool bfs()
{
    while(!q.empty()) q.pop();
    for(int i=src;i<=decc;i++) lev[i]=-1,cur[i]=front[i];
    lev[src]=0; 
    q.push(src);
    int now;
    while(!q.empty())
    {
        now=q.front(); q.pop();
        for(int i=front[now];i;i=nxt[i])
        {
            if(lev[to[i]]==-1&&val[i]>0)
            {
                lev[to[i]]=lev[now]+1;
                if(to[i]==decc) return true;
                q.push(to[i]);
            }
        }
    }
    return false;
}
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(lev[to[i]]>lev[now]&&val[i]>0)
        {
            delta=dinic(to[i],min(flow-rest,val[i]));
            if(delta)
            {
                val[i]-=delta; val[i^1]+=delta;
                rest+=delta; if(rest==flow) break;
            }
        }
    }
    if(rest==flow) lev[now]=-1;
    return rest;
}

bool check(int mid)
{
    rebuild(mid);
    int maxflow=0;
    while(bfs()) 
    maxflow+=dinic(src,2e9);
    return maxflow==n*mid;
}

int main()
{
    read(n); read(k);
    decc=n*4+1;
    for(int i=1;i<=n;++i)
    {
        scanf("%s",s+1);
        for(int j=1;j<=n;++j) mp[i][j]=s[j]=='Y' ? true : false; 
    }
    int l=0,r=n,mid,ans;
    while(l<=r)
    {
        mid=l+r>>1;
        if(check(mid)) ans=mid,l=mid+1;
        else r=mid-1; 
    }
    cout<<ans;
}

 

1305: [CQOI2009]dance跳舞

Time Limit: 5 Sec  Memory Limit: 162 MB
Submit: 3691  Solved: 1565
[Submit][Status][Discuss]

Description

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

Input

第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为'Y'当且仅当男孩i和女孩j相互喜欢。

Output

仅一个数,即舞曲数目的最大值。

Sample Input

3 0
YYY
YYY
YYY

Sample Output

3

HINT

 

N<=50 K<=30

posted @ 2017-12-10 22:21  TRTTG  阅读(261)  评论(0编辑  收藏  举报