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

时间: 2024-10-10 03:45:09

bzoj千题计划130:bzoj1305: [CQOI2009]dance跳舞的相关文章

BZOJ-1305: [CQOI2009]dance跳舞(最大流 增加超级源汇+分裂点+二分 水题)

1305: [CQOI2009]dance跳舞 Time Limit: 5 Sec  Memory Limit: 162 MB Description 一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲.有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”).每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞.给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲? Inpu

bzoj1305: [CQOI2009]dance跳舞(二分答案+网络流)

1305: [CQOI2009]dance跳舞 题目:传送门 题解: 一眼网络流基础建模...然后就GG了 二分答案+拆点建边+最大流判断: 把男女生拆为男1,男2,女1,女2 1.男1和男2还有女1和女2之间连边,流量为约束条件k 2.st连男1,女2连ed,流量为二分的mid 3.如果男生i喜欢女生j,就将男1与女2相连(不在约束条件内) 4.如果不喜欢,就将男2与女1相连(在约束条件内) 代码: 1 #include<cstdio> 2 #include<cstring> 3

bzoj千题计划175:bzoj1303: [CQOI2009]中位数图

http://www.lydsy.com/JudgeOnline/problem.php?id=1303 令c[i]表示前i个数中,比d大的数与比d小的数的差,那么如果c[l]=c[r],则[l+1,r]满足条件 #include<cstdio> #include<iostream> using namespace std; const int N=1e7; int c[N*2],g[N]; void read(int &x) { x=0; char c=getchar()

bzoj千题计划233:bzoj 1304: [CQOI2009]叶子的染色

http://www.lydsy.com/JudgeOnline/problem.php?id=1304 结论1:根节点一定染色 如果根节点没有染色,选择其子节点的一个颜色,那么所有这个颜色的子节点都不用染色.答案不会更差. 结论2:相邻节点不会染同一种颜色 将深度更大的那个有色节点变成无色仍然满足要求 结论3:任意一个非叶子节点做根,对答案都没有影响. 考虑将原根节点的一个自己点换成根,原来到根最近的颜色节点不变 所以,任取一个非叶子节点做根 dp[x][0/1]表示x染黑/白,使其子树内叶子

bzoj千题计划185:bzoj1260: [CQOI2007]涂色paint

http://www.lydsy.com/JudgeOnline/problem.php?id=1260 区间DP模型 dp[l][r] 表示涂完区间[l,r]所需的最少次数 从小到大们枚举区间[l,r] 如果col[l]==col[r] dp[l][r]=min(dp[l+1][r],dp[l][r-1],dp[l+1][r-1]+1) 否则 dp[l][r]=min(dp[l][k]+dp[k+1][r]) 我还是辣鸡啊~~~~(>_<)~~~~,这种题都不能秒 #include<c

bzoj千题计划292:bzoj2244: [SDOI2011]拦截导弹

http://www.lydsy.com/JudgeOnline/problem.php?id=2244 每枚导弹成功拦截的概率 = 包含它的最长上升子序列个数/最长上升子序列总个数 pre_len [i] 表示以i结尾的最长不下降子序列的长度 pre_sum[i] 表示对应长度下的方案数 suf_len[i] 表示以i开头的最长不下降子序列长度 suf_sum[i] 表示对应长度下的方案数 若已有了这4个数组 设最长上升子序列长度=mx 那么 如果pre_len[i]+suf_len[i] -

bzoj千题计划304:bzoj3676: [Apio2014]回文串

https://www.lydsy.com/JudgeOnline/problem.php?id=3676 回文自动机模板题 4年前的APIO如今竟沦为模板,,,╮(╯▽╰)╭,唉 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 300001 char ss[N]; int s[N]; int tot=1,last; int fail[N],len

bzoj千题计划106:bzoj1014 [JSOI2008]火星人prefix

http://www.lydsy.com/JudgeOnline/problem.php?id=1014 两个后缀的最长公共前缀:二分+hash 带修改带插入:splay维护 #include<cstdio> #include<cstring> #include<iostream> #define L 100001 typedef unsigned long long ULL; using namespace std; char s[L+4]; int tot,root

bzoj千题计划108:bzoj1018: [SHOI2008]堵塞的交通traffic

http://www.lydsy.com/JudgeOnline/problem.php?id=1018 关键点在于只有两行 所以一个2*m矩形连通情况只有6种 编号即对应代码中的a数组 线段树维护 用b数组表示 节点第0/1行的最右一列是否连接了右边 来 辅助 节点的合并 查询 对两个点位于矩形的位置分4种情况讨论 两点是否联通,要考虑四种情况 (以两个位置是矩形左上角和右上角为例) 1.直接联通,线段树的节点包含了这种情况,直接判断 2. 3. 4. 后三种情况需要再查询[1,l]和[r,n