P3153 [CQOI2009]跳舞

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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


分析

首先看的出这道题是一个匹配问题,自然联想到网络流算法

既然是网络流,那么就一定有网络容量来达到限制的目的,最后对应题意的要求。而通过题意找限制条件,构建模型最后用最大流求解,是最大流类题目的核心解法

现在我们来看看这题有什么限制:

1.所有男孩/女孩都要跳舞,不能在旁边干看着

2.不会和同一人跳舞

3.只能和k个不喜欢的人跳舞

依据这些条件,我们怎么构建模型呢?

建模

我们一个一个分析:

1.都要跳舞

既然不能干看着,那么一首舞曲中,每个人都得跳,换言之,若是本题答案为ans,那么最终每人都能跳ans只舞,

所以我们二分答案,在某个模型下跑最大流,最后检查答案,若满足条件:(跳舞的总数就是ans * N(人数))我们就往上搜,否则就往下搜,不断缩小二分范围,找到答案 (其实貌似数据范围可以直接枚举)

2.不会和同一人跳舞

匹配的基本知识,男女连边容量为1即可,不再赘述

3.能和k个不喜欢的人跳舞

我们要求能跳舞的场数最多,自然就想k尽可能多一点,虽然k是不能改变的,但是依据贪心的思想,我们能不用k就尽量不用k,换言之,如果和舞伴互相喜欢,就不用消耗k的次数了。

为了达到喜欢的人互相跳舞不消耗k,我们需要分裂点:将每个男/女分裂为喜欢和不喜欢两个部分,然后连边如下图

a为二分出来的答案

源点连男容量为a保证了一个人可以跳a场舞,来进行最大流以及答案验证

(深色为喜欢,浅一点为不喜欢)

若两人相互喜欢,则有:

这样直接连喜欢,s到t的路上没有占用k,即k的次数无消耗;容量为1保证了只和同一人跳一次舞


若两人不互相喜欢,则有

不喜欢的人跳舞不愿意,需要消耗k,路径被夹在k之间,最大流从之间通过消耗k,达到目的;容量为1同样保证了只和同一人跳一次舞

建模完毕

最后跑最大流,验证是否合法,继续二分即可得到最终答案

注:重复建图记得初始化

AC Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int RD(){
int out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const int maxn = 100019,INF = 1e9;
int num,k,nume = 1;
int dance[190][190];
int s,t,maxflow;
int head[maxn << 2];
struct Node{
int v,dis,nxt;
}E[maxn << 3];
void add(int u,int v,int dis){
E[++nume].nxt = head[u];
E[nume].v = v;
E[nume].dis = dis;
head[u] = nume;
}
int d[maxn];
bool bfs(){
queue<int>Q;
memset(d,0,sizeof(d));
d[s] = 1;
Q.push(s);
while(!Q.empty()){
int u = Q.front();Q.pop();
for(int i = head[u];i;i = E[i].nxt){
int v = E[i].v;
if(E[i].dis && !d[v]){
d[v] = d[u] + 1;
if(v == t)return 1;
Q.push(v);
}
}
}
return 0;
}
int Dinic(int u,int flow){
if(u == t)return flow;
int rest = flow,k;
for(int i = head[u];i;i = E[i].nxt){
int v = E[i].v;
if(d[v] == d[u] + 1 && rest && E[i].dis){
k = Dinic(v,min(rest,E[i].dis));
if(!k)d[v] = 0;
E[i].dis -= k;
E[i ^ 1].dis += k;
rest -= k;
}
}
return flow - rest;
}
void build(int a){
memset(head,0,sizeof(head));
nume = 1;//初始化
for(int i = 1;i <= num;i++){
add(s,i,a);
add(i,s,0);//连汇点到男生喜欢
add(i,i + num,k);
add(i + num,i,0);//连男喜欢到不喜欢
add(i + 2 * num,i + 3 * num,k);
add(i + 3 * num,i + 2 * num,0);//连女不喜欢到喜欢
add(i + 3 * num,t,a);
add(t,i + 3 * num,0);//女喜欢到源点
}
for(int i = 1;i <= num;i++){
for(int j = 1;j <= num;j++){
if(dance[i][j]){
add(i,j + 3 * num,1);
add(j + 3 * num,i,0);
}
else{
add(i + num,j + 2 * num,1);
add(j + 2 * num,i + num,0);
}
}
}
}
bool check(int mid){
build(mid);
maxflow = 0;
int flow = 0;
while(bfs())while(flow = Dinic(s,INF))maxflow += flow;
if(maxflow == mid * num)return 1;
return 0;
}
int search(int l,int r){
int ans;
while(l <= r){
int mid = l + r >> 1;
if(check(mid))l = mid + 1,ans = mid;
else r = mid - 1;
}
return ans;
}
int main(){
num = RD();k = RD();
char temp;
for(int i = 1;i <= num;i++){
for(int j = 1;j <= num;j++){
cin>>temp;
if(temp == 'Y')dance[i][j] = 1;
}
}
s = num * 4 + 1;t = s + 1;
printf("%d\n",search(0,num + k));
return 0;
}

题解 P3153 【[CQOI2009]跳舞】的更多相关文章

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

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

  2. 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. 简单主机批量管理工具(这里实现了paramiko 用su切换到root用户)

    项目名:简单主机批量管理工具 一.需求 1.主机分组 2.可批量执行命令.发送文件,结果实时返回,执行格式如下 batch_run  -h h1,h2,h3   -g web_clusters,db_ ...

  2. 如何选择合适的Qt5版本?

    注意:这里讨论的是在不编译Qt源码的情况下,推荐下载的官方编译版本. 支持XP SP3以及之后的Windows版本:推荐 Qt5.6 或 Qt5.9,这两个版本是LTS版本(即长期支持版本),Bug较 ...

  3. HTMLA内联框架

    <head> <meta charset="utf-8" /> <title>内联框架</title> </head> ...

  4. Scrum团队成立及《构建之法》第六、七章读后感

    5.Scrum团队成立 5.1 团队名称:喳喳      团队目标:突破渣渣      团队口号:吱吱喳喳      团队照: 5.2 角色分配 产品负责人: 112冯婉莹 Scrum Master: ...

  5. ZY、

  6. Mac下Git的基础操作

    目前最火的版本控制软件是Git了吧,今天简单梳理一下Mac下Git的基础操作~~ 一.什么是Git Git是一个分布式代码管理工具,用于敏捷的处理或大或小的项目,类似的工具还有svn. 基于Git的快 ...

  7. laravel连接多个不同数据库的单例类

    在連接多個不同數據庫時,需要寫多個連接,爲了簡化該操作,可以使用該基類,不同的數據庫只要建立好相對應的類繼承該類,就可以使用ORM模型進行操作了. class singletonInstance { ...

  8. 这套C#编码规范写不错

    自己总结的C#编码规范--1.命名约定篇:http://www.cnblogs.com/luzhihua55/p/CodingConventions1.html 自己总结的C#编码规范--2.命名选择 ...

  9. 第128天:less简单入门

    一.预处理 Less 1.官网文件 > 一款比较流行的预处理CSS,支持变量.混合.函数.嵌套.循环等特点> [官网](http://lesscss.org/)> [中文网](htt ...

  10. Spring Cloud Sleuth服务跟踪

    监控 使用zipkin(https://zipkin.io/) 监控服务构建: (普通的springBoot项目) <!--引入的zipkinServer依赖--> <depende ...