【题目大意】

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

【思路】

假设当前有a首舞曲。

把每个人拆成两个点,从“喜欢”到“不喜欢”连一条容量为k的边。从S往“男孩喜欢”连一条容量为a的边,从“女孩喜欢”往T连一条容量为a的边。

然后对于每对男孩女孩,如果不喜欢,则从“男孩不喜欢”到“女孩不喜欢”连一条容量为1的边,否则从“男孩喜欢”到“女孩喜欢”连一条容量为1的边。

为什么这个是正确的呢?这样相当于喜欢的人之间限制住了至多跳一首,而最多和k个不喜欢的人跳舞。画图感受一下就好了。

如果这a首舞曲都能用到,那么这个网络流应该是满流的。

所以二分答案。

注意很重要的两点:

①二分最后ub还要单独判断一下。

②不要忘了每次E的容量会被修改,所以暂存到rE每次重新回到原始状态。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define INF 0x7fffffff
#define S 0
#define T 4*n+1
using namespace std;
struct node
{
int to,pos,cap;
};
const int MAXN=+;
int n,k;
vector<node> E[MAXN*+];
vector<node> tmpE[MAXN*+];
int dis[MAXN*+]; void addedge(int u,int v,int w)
{
tmpE[u].push_back((node){v,tmpE[v].size(),w});
tmpE[v].push_back((node){u,tmpE[u].size()-,});
E[u].push_back((node){v,E[v].size(),w});
E[v].push_back((node){u,E[u].size()-,});
} bool bfs()
{
memset(dis,-,sizeof(dis));
queue<int> que;
while (!que.empty()) que.pop();
que.push(S);
dis[S]=;
while (!que.empty())
{
int head=que.front();que.pop();
if (head==T) return true; //首次抵达T即可返回,不需要整张图全部分层
for (int i=;i<E[head].size();i++)
{
node tmp=E[head][i];
if (dis[tmp.to]==- && tmp.cap)
{
dis[tmp.to]=dis[head]+;
que.push(tmp.to);
}
}
}
return false;
} int dfs(int s,int e,int f)
{
if (s==e) return f;
int ret=;
for (int i=;i<E[s].size();i++)
{
node &tmp=E[s][i];
if (dis[tmp.to]==dis[s]+ && tmp.cap)
{
int delta=dfs(tmp.to,e,min(f,tmp.cap));
if (delta>)
{
tmp.cap-=delta;
E[tmp.to][tmp.pos].cap+=delta;
f-=delta;
ret+=delta;
if (f==) return ret;
}
else dis[tmp.to]=-;
}
}
return ret;
} int dinic()
{
int flow=;
while (bfs())
{
int f=dfs(S,T,INF);
if (f) flow+=f;else break;
}
return flow;
} void init()
{
scanf("%d%d",&n,&k);
//0 源点
//1~n 男性喜欢
//n+1~2n 男性不喜欢
//2n+1~3n 女性不喜欢
//3n+1~4n 女性喜欢
//4n+1 汇点
for (int i=;i<=n;i++) addedge(i,i+n,k);
for (int i=*n+;i<=*n;i++) addedge(i,i+n,k);
for (int i=;i<=n;i++)
{
char str[MAXN];
scanf("%s",str+);
for (int j=;j<=n;j++)
{
if (str[j]=='Y') addedge(i,*n+j,);
else addedge(n+i,*n+j,);
}
}
for (int i=;i<=n;i++) addedge(S,i,);
for (int i=*n+;i<=*n;i++) addedge(i,T,);
} void solve()
{
int lb=,ub=n;
while (lb+<ub)
{
for (int i=S;i<=T;i++)
for (int j=;j<E[i].size();j++) E[i][j]=tmpE[i][j];
int mid=(lb+ub)>>;
for (int i=;i<n;i++) E[S][i].cap=mid;
for (int i=*n+;i<=*n;i++) E[i][E[i].size()-].cap=mid;
int d=dinic();
if (d==mid*n) lb=mid;else ub=mid;
}
for (int i=S;i<=T;i++)
for (int j=;j<E[i].size();j++) E[i][j]=tmpE[i][j];
for (int i=;i<n;i++) E[S][i].cap=ub;
for (int i=*n+;i<=*n;i++) E[i][E[i].size()-].cap=ub;
int d=dinic();
printf("%d",(d==ub*n)?ub:lb);
} int main()
{
init();
solve();
return ;
}

【最大流】BZOJ1305-[CQOI2009]dance跳舞的更多相关文章

  1. BZOJ1305 [CQOI2009]dance跳舞 【网络流】

    1305: [CQOI2009]dance跳舞 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 3714  Solved: 1572 [Submit][ ...

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

    1305: [CQOI2009]dance跳舞 题目:传送门 题解: 一眼网络流基础建模...然后就GG了 二分答案+拆点建边+最大流判断: 把男女生拆为男1,男2,女1,女2 1.男1和男2还有女1 ...

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

    http://www.lydsy.com/JudgeOnline/problem.php?id=1305 每个人拆为喜欢(yes)和不喜欢(no)两个点 二分答案 1.每两个人之间只能跳一次 喜欢则 ...

  4. 【二分答案】【最大流】bzoj1305 [CQOI2009]dance跳舞

    http://hzwer.com/1986.html #include<cstdio> #include<algorithm> #include<queue> #i ...

  5. Bzoj1305 [CQOI2009]dance跳舞

    Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 2925  Solved: 1221 Description 一次舞会有n个男孩和n个女孩.每首曲子开始时 ...

  6. 并不对劲的bzoj1305: [CQOI2009]dance跳舞

    传送门-> 又是陈年老坑. 听上去不知道从何下[手]?那要是把题目换成“判断这些人能否条x支舞”呢? 这样就变成了一个网络流可以解决的问题,只要把每个人拆成喜欢和不喜欢两点,每个人两点总流量不超 ...

  7. BZOJ 1305: [CQOI2009]dance跳舞 二分+最大流

    1305: [CQOI2009]dance跳舞 Description 一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲 ...

  8. [CQOI2009]dance跳舞(最大流+二分)

    [CQOI2009]dance跳舞 每个人拆成$2$个点,表示是否与喜欢的人跳舞 跳$m$首舞曲时,满足最大流为$n*m$ 二分$m$,跑最大流即可 #include<cstdio> #i ...

  9. BZOJ 1305: [CQOI2009]dance跳舞( 最大流 )

    云神代码很短...0 ms过的...看了代码 , 大概是贪心... orz 我不会证 数据这么小乱搞就可以了吧... ←_← 这道题网络流还是可以写的... 既然限制了最多只能和 k 个不喜欢的人da ...

  10. AC日记——[CQOI2009]DANCE跳舞 洛谷 P3153

    [CQOI2009]DANCE跳舞 思路: 二分+最大流: 代码: #include <cstdio> #include <cstring> #include <iost ...

随机推荐

  1. arch中yaourt的安装和使用

    yaourt-Yet AnOther User Repository Tool Yaourt是archlinux方便使用的关键部件之一,但没有被整合到系统安装中的工具.建议在装完系统重启之后,更新完p ...

  2. [Leetcode Week16]Range Sum Query - Mutable

    Range Sum Query - Mutable 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/range-sum-query-mutable/de ...

  3. free函数在操作系统内存中的实现【转】

    转自:http://www.2cto.com/kf/201210/160985.html 我一次性malloc十个单位节点的内存空间出来赋值给L, 现在我想一次性删除从第3个到第6个节点,我是这么做的 ...

  4. centos_7.1.1503_src_2

    farstream02-0.2.3-3.el7.src.rpm 05-Jul-2014 12:59 1.2M   fcoe-utils-1.0.29-9.el7.src.rpm 31-Mar-2015 ...

  5. SVN使用详解

    一.SVN的使用 项目经理使用,写好项目框架.文档等. 李四(程序员)的使用,在项目经理写好的框架上进行开发. 二.SVN三大指令 Checkout(检出操作): 连接到svn服务器 更新服务器数据到 ...

  6. RabbitMQ 实践及使用

    目录 - 1. RabbitMQ的安装    - 1.1 配置好 epel    - 1.2 安装 RPM包    - 1.3 创建用户设置权限- 2. RabbitMQ组件- 3. RabbitMQ ...

  7. [ python ] 项目二:主机批量管理程序

    开发要求: 1. 对主机进行批量管理    2. 可对单台或主机组批量执行命令    3. 可上传文件到对应的主机或组    4. 使用多线程实现  程序: 1. README # 作者:hkey # ...

  8. 【Java基础】重写equals需要重写hashcode

    Object里的equals用来比较两个对象的相等性,一般情况下,当重写这个方法时,通常有必要也重写hashcode,以维护hashcode方法的常规协定,或者说这是JDK的规范,该协定声明相等对象必 ...

  9. Leetcode 之Balanced Binary Tree(49)

    用递归的方式来做,左右两棵子树的高度差不超过1.分成两部分,一部分递归得到树的高度,一部分递归检查左右子树是否是平衡二叉树. int getHeight(TreeNode *root) { ; ; } ...

  10. NOIP 2013 day1

    tags: 模拟 快速幂 逆序对 树状数组 归并排序 最小生成树 lca 倍增 categories: 信息学竞赛 总结 tex live 2017.iso 转圈游戏 火柴排队 货车运输 转圈游戏 s ...