题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

3 0
YYY
YYY
YYY
输出样例#1:

3

说明

N<=50 K<=30

Solution:

  本题太毒,调了几天,终于又填完坑了~

  像这种需要配对,而且数据还这么小的题目,一眼就容易想到网络最大流。

  那么如果直接去跑最大流的话,显然不可行。

  题意中说相同的两个人只能搭配一次,那么最多也就$50$次,很容易想到从大到小枚举天数然后跑最大流判断(我写了下枚举+最大流,事实证明是可以过的),但是,本题有很明显的单调性,即若前$i$天可以完整搭配,则答案一定在$[i,n]$之间,否则就在$[0,i-1]$之间。于是考虑二分答案,然后跑最大流$check$。

  再来考虑最大流$check$是否可行。每个男生的点和女生的点相匹配,只有两种情况,要么不互相喜欢使用$1$次限制,要么互相喜欢不需要花费。

  因为每人最多和不喜欢的匹配$k$次,于是我们将每个学生都拆成两个点,之间连边为$k$表示限制,假设男生$a$被拆为$a1,a2$($a1$是$a$的全局,$a2$是与$a$不互相喜欢的分点),女生$b$被拆为$b1,b2$(类比男生的含义),每次二分的天数$x$,重新建图:$s\rightarrow a1$连容量为$x$($s$为源点,该边表示每个人应该匹配$x$次),$a1\rightarrow a2$连容量为$k$(表示$a$最多和$k$个不喜欢的女生匹配),$b1,b2$类比男生连法($b2\rightarrow b1\;\;b1\rightarrow t$)。每次若男生$a$和女生$b$不喜欢,连容量为$1$的边$a2\rightarrow b2$,若$a$和$b$互相喜欢,则应直接连容量为$1$的边$a1\rightarrow b1$。

  然后每次跑完最大流后,看最大流是否等于$x*n$,便能判断是否成立。(最后需要注意的是二分的边界值:$l=0,r=n$,最少就是$1$次也无法搭配,最多就是$n$人互相搭配一次)

代码:

#include<bits/stdc++.h>
#define il inline
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define Min(a,b) ((a)>(b)?(b):(a))
#define debug printf("%d %s\n",__LINE__,__FUNCTION__)
using namespace std;
const int N=,inf=;
int s,t=,ans,dis[],n,k,to[N],net[N],h[],cnt=,w[N];
bool mp[][]; il void add(int u,int v,int c){to[++cnt]=v,net[cnt]=h[u],h[u]=cnt,w[cnt]=c;} il bool bfs(){
queue<int>q;
memset(dis,-,sizeof(dis));
q.push(s),dis[s]=;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=h[u];i;i=net[i])
if(dis[to[i]]==-&&w[i]>)dis[to[i]]=dis[u]+,q.push(to[i]);
}
return dis[t]!=-;
} il int dfs(int u,int op){
if(u==t)return op;
int flow=,used=;
for(int i=h[u];i;i=net[i]){
int v=to[i];
if(dis[v]==dis[u]+&&w[i]>){
used=dfs(v,Min(w[i],op));
if(!used)continue;
flow+=used,op-=used;
w[i]-=used,w[i^]+=used;
if(!op)break;
}
}
if(!flow)dis[u]=-;
return flow;
} il bool check(int x){
memset(h,,sizeof(h));
cnt=;
For(i,,n){
add(s,i,x),add(i,s,);
add(i,i+n,k),add(i+n,i,);
add(i+n*,t,x),add(t,i+n*,);
add(i+n*,i+n*,k),add(i+n*,i+n*,);
}
For(i,,n) For(j,,n){
if(mp[i][j])add(i,j+*n,),add(j+*n,i,);
else add(i+n,j+*n,),add(j+*n,i+n,);
}
int tot=;
while(bfs())tot+=dfs(s,inf);
if(tot==n*x)return ;
return ;
} int main(){
ios::sync_with_stdio();
cin>>n>>k;
char p;
For(i,,n) For(j,,n) {
cin>>p;
if(p=='Y')mp[i][j]=;
if(n==&&(p=='Y'||k>=)){cout<<;return ;}
}
int mid,l=,r=n;
while(l<=r){
mid=l+r>>;
if(check(mid))l=mid+,ans=mid;
else r=mid-;
}
cout<<ans;
return ;
}

P3153 [CQOI2009]跳舞的更多相关文章

  1. [洛谷P3153] [CQOI2009]跳舞

    题目大意:有n个女生,n个男生,每次一男一女跳舞.同一队只会跳一次.每个男孩最多只愿意和k个不喜欢的女孩跳舞,女孩同理.问舞会最多能有几首舞曲? 题解:二分跳了多少次舞,每次重建图,建超级原点和汇点, ...

  2. 题解 P3153 【[CQOI2009]跳舞】

    P3153 [CQOI2009]跳舞 题目描述 一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲.有一些男孩女孩相互喜欢 ...

  3. [CQOI2009]跳舞 网络流

    题面:[CQOI2009]跳舞 题解: 首先最大时间不好求,而且数据范围很小,所以我们可以先二分一个最大时间,然后就只需要判断是否可行即可. 因此我们每二分一个mid,对于每个女生,连s ---> ...

  4. [BZOJ1305][CQOI2009]跳舞(网络流)

    1305: [CQOI2009]dance跳舞 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 3944  Solved: 1692[Submit][St ...

  5. [CQOI2009]跳舞

    思路:二分答案+最大流.二分答案$m$,表示最多跳$m$轮.将每个人拆成两个点$a_i$$b_i$,$a_i$表示与任何人跳舞,$b_i$表示与不喜欢的人跳舞.对于第$i$个人,连一条从$a_i$到$ ...

  6. 1305. [CQOI2009]跳舞【最大流+二分】

    Description 一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲.有一些男孩女孩相互喜欢,而其他相互不喜欢(不会 ...

  7. 【[CQOI2009]跳舞】

    首先这种匹配类问题一看就是网络流了 之后想一想怎么搞 发现题目的意思是使得跳舞最少的男生跳的舞最多 很自然想到二分答案啊 现在转化成了一个判定性问题,能否使得所有人都跳上\(k\)只舞 由于喜欢和不喜 ...

  8. 题解 P1682 【过家家】

    P1682 过家家 题目描述 有2n个小学生来玩过家家游戏,其中有n个男生,编号为1到n,另外n个女生,编号也是1到n.每一个女生可以先选择一个和她不吵嘴的男生来玩,除此之外,如果编号为X的女生的朋友 ...

  9. AHOI2018训练日程(3.10~4.12)

    (总计:共90题) 3.10~3.16:17题 3.17~3.23:6题 3.24~3.30:17题 3.31~4.6:21题 4.7~4.12:29题 ZJOI&&FJOI(6题) ...

随机推荐

  1. iOS网络图片缓存详解

    在开发移动应用的时候比如Android,IOS,因为手机流量.网速.内存等这些因素,当我们的移动应用是针对互联网,并要频繁访问网络的话,对网络优化这块就显得尤为重要了. 比如某个应用要经常显示网络图片 ...

  2. Linux常见文件管理命令

    1.Linux上的文件管理类命令都有哪些,其常用的使用方法及其相关示例演示.(1)目录管理命令——ls:列出指定目录下的内容格式:ls [OPTION]... [FILE]... -a:显示所有文件包 ...

  3. Centos7 使用LVM进行新加磁盘管理

    centos7使用LVM管理一块新的磁盘   注意!文中凡是带#的都是命令标志.   一些重要概念: LV(Logical Volume)- 逻辑卷, VG(Volumne Group)- 卷组, P ...

  4. linux C 数组与指针

    linux C 数组与指针 一.数组 数组是同一数据类型的一组值:属于引用类型,因此数组存放在堆内存中:数组元素初始化或给数组元素赋值都可以在声明数组时或在程序的后面阶段进行. 定义一维数组的一般格式 ...

  5. 最小化 Java 镜像的常用技巧

    背景 随着容器技术的普及,越来越多的应用被容器化.人们使用容器的频率越来越高,但常常忽略一个基本但又非常重要的问题 - 容器镜像的体积.本文将介绍精简容器镜像的必要性并以基于 spring boot ...

  6. 【转载】C#批量插入数据到Sqlserver中的三种方式

    引用:https://m.jb51.net/show/99543 这篇文章主要为大家详细介绍了C#批量插入数据到Sqlserver中的三种方式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 本篇, ...

  7. python爬虫:利用BeautifulSoup爬取链家深圳二手房首页的详细信息

    1.问题描述: 爬取链家深圳二手房的详细信息,并将爬取的数据存储到Excel表 2.思路分析: 发送请求--获取数据--解析数据--存储数据 1.目标网址:https://sz.lianjia.com ...

  8. Cache、Buffer的区别

    什么是Cache?什么是Buffer?二者的区别是什么? Buffer和Cache的区别 buffer与cache操作的对象就不一样. 1.buffer(缓冲)是为了提高内存和硬盘(或其他I/O设备) ...

  9. [CodeForces954G]Castle Defense(二分答案+差分)

    Description 题目链接 Solution 二分答案,套一个差分标记即可 每次放弓箭手显然越右边越优 Code #include <cstdio> #include <alg ...

  10. samba server on Mac OS X Lion Server

    一般Mac共享通过配置wins,smb即可实现.注意在同一个工作组! 参考:http://computers.tutsplus.com/tutorials/how-to-set-up-an-smb-s ...