[CQOI2009]跳舞 网络流
题解:
首先最大时间不好求,而且数据范围很小,所以我们可以先二分一个最大时间,然后就只需要判断是否可行即可。
因此我们每二分一个mid,对于每个女生,连s ---> x : mid , x ---> x' : k.对于每个男生,连x ---> t : mid, x' ---> x : k.
对于每条边,如果为Y,连x ---> y.否则连x' ---> y'.
其中x和x'分别表示一个人和这个人拆分出来的点。
为什么这么连?
对于每个女生,连s ---> x : mid , x ---> x' : k。 其中s ---> x : mid 表示一共要进行mid次,x ---> x' : k表示这mid次中最多可以选k个和不喜欢的人相连。
对于每个男生,连x ---> t : mid, x' ---> x : k. 同上。
对于每条边,如果为Y,连x ---> y.否则连x' ---> y'. 如果是Y,说明互相喜欢,所以用原本的点相连,否则说明互相不喜欢,就用拆分出的点相连。因为拆分出的点最多只有k次机会,因此表示的是连向不喜欢的点。
我一开始是这么想的,但是为了看上去简单一点,对于每个女生,我连了s --- > x : lim - k, s --- > x' : k.
这样是不对的,因为这样就固定了喜欢的人也最多选lim - k个,而实际上是没有这个限制的。因此我们用x ---> x' : k的方法就可以去掉这个限制,并且可以让它相对动态的分配每次机会,而不是每次固定的只能选lim - k次喜欢的,和强制选k次不喜欢的。
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 400
#define ac 40000
#define inf 1000000000 int n, m, ans, all, sum, s, t, head, tail, x, addflow, k;
int Head[AC], Next[ac], date[ac], haveflow[ac], tot = ;
int have[AC], c[AC], good[AC], last[AC], q[ac];
char f[AC][AC]; inline int read()
{
int x = ;char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} void init()
{
memset(Head, , sizeof(Head));
memset(have, , sizeof(have));
memset(c, , sizeof(c));
ans = , tot = ;
} inline void add(int f, int w, int S)
{
date[++ tot] = w, Next[tot] = Head[f], Head[f] = tot, haveflow[tot] = S;
date[++ tot] = f, Next[tot] = Head[w], Head[w] = tot, haveflow[tot] = ;
//printf("%d %d : %d\n", f, w, S);
} inline void upmin(int &a, int b){
if(b < a) a = b;
} void build(int lim)
{
sum = lim * m;
for(R i = ; i <= n; i ++) add(s, i, lim), add(i, n + i, k);
for(R i = ; i <= n; i ++)
for(R j = ; j <= m; j ++)
{
if(f[i][j] == 'Y') add(i, n + n + j, );
else add(n + i, n + n + m + j, );
}
for(R i = ; i <= m; i ++) add(n + n + i, t, lim), add(n + n + m + i, n + n + i, k);
} void bfs()
{
head = tail = ;
q[++ tail] = t, c[t] = , have[] = ;
while(head < tail)
{
int x = q[++ head];
for(R i = Head[x]; i; i = Next[i])
{
int now = date[i];
if(!c[now] && haveflow[i ^ ])
++ have[c[now] = c[x] + ], q[++ tail] = now;
}
}
memcpy(good, Head, sizeof(Head));
} void aru()
{
while(x != s)
{
haveflow[last[x]] -= addflow;
haveflow[last[x] ^ ] += addflow;
x = date[last[x] ^ ];
}
ans += addflow;
} void isap()
{
bool done = false;
x = s, addflow = inf;
while(c[s] != all)
{
if(x == t) aru(), addflow = inf;
done = false;
for(R i = good[x]; i; i = Next[i])
{
int now = date[i];
good[x] = i;
if(c[now] == c[x] - && haveflow[i])
{
done = true, x = now, last[now] = i;
upmin(addflow, haveflow[i]);
break;
}
}
if(!done)
{
int go = all - ;
for(R i = Head[x]; i; i = Next[i])
if(c[date[i]] && haveflow[i]) upmin(go, c[date[i]]);
if(!(-- have[c[x]])) break;
++ have[c[x] = go + ], good[x] = Head[x];
if(x != s) x = date[last[x] ^ ];
}
}
} bool check(int lim)
{
init(), build(lim), bfs(), isap();
if(ans == sum) return true;
else return false;
} void half()
{
int l = , r = n, mid;
while(l < r)
{
mid = (l + r + ) >> ;
if(check(mid)) l = mid;
else r = mid - ;
}
printf("%d\n", l);
} void pre()
{
n = read(), m = n, k = read();
s = n + n + m + m + , t = s + , all = t + ;
for(R i = ; i <= n; i ++) scanf("%s", f[i] + );
} int main()
{
freopen("in.in", "r", stdin);
pre();
half();
fclose(stdin);
return ;
}
[CQOI2009]跳舞 网络流的更多相关文章
- [BZOJ1305][CQOI2009]跳舞(网络流)
1305: [CQOI2009]dance跳舞 Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 3944 Solved: 1692[Submit][St ...
- 题解 P3153 【[CQOI2009]跳舞】
P3153 [CQOI2009]跳舞 题目描述 一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲.有一些男孩女孩相互喜欢 ...
- [CQOI2009]跳舞
思路:二分答案+最大流.二分答案$m$,表示最多跳$m$轮.将每个人拆成两个点$a_i$$b_i$,$a_i$表示与任何人跳舞,$b_i$表示与不喜欢的人跳舞.对于第$i$个人,连一条从$a_i$到$ ...
- 1305. [CQOI2009]跳舞【最大流+二分】
Description 一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲.有一些男孩女孩相互喜欢,而其他相互不喜欢(不会 ...
- 【[CQOI2009]跳舞】
首先这种匹配类问题一看就是网络流了 之后想一想怎么搞 发现题目的意思是使得跳舞最少的男生跳的舞最多 很自然想到二分答案啊 现在转化成了一个判定性问题,能否使得所有人都跳上\(k\)只舞 由于喜欢和不喜 ...
- [洛谷P3153] [CQOI2009]跳舞
题目大意:有n个女生,n个男生,每次一男一女跳舞.同一队只会跳一次.每个男孩最多只愿意和k个不喜欢的女孩跳舞,女孩同理.问舞会最多能有几首舞曲? 题解:二分跳了多少次舞,每次重建图,建超级原点和汇点, ...
- P3153 [CQOI2009]跳舞
题目描述 一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲.有一些男孩女孩相互喜欢,而其他相互不喜欢(不会”单向喜欢“) ...
- 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题) ...
- 题解 P1682 【过家家】
P1682 过家家 题目描述 有2n个小学生来玩过家家游戏,其中有n个男生,编号为1到n,另外n个女生,编号也是1到n.每一个女生可以先选择一个和她不吵嘴的男生来玩,除此之外,如果编号为X的女生的朋友 ...
随机推荐
- Java多线程之volatile与synchronized比较
可见性: JAVA内存模型: java为了加快程序的运行效率,对一些变量的操作是在寄存器或者CPU缓存上进行的,后面再同步到主存中 看上图,线程在运行的过程中,会从主内存里面去去变量,读到自己的空间内 ...
- hdu1231最大连续子序列(动态规划)
最大连续子序列 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Sub ...
- 测试开发的成长之路 - 自动化一站式平台(UI、接口)
前言 在自动化测试过程中,随着对接的自动化需求不断增加,测试用例数量显著上升,参与自动化测试的人也越来越多,多人协作就会碰到很多问题,包括脚本.数据.版本.项目整合.持续集成等,而且也增加了后期维护的 ...
- 各种对list,string操作函数的总结
#encoding=utf-8#reverse,用来反转lista=['aa','bb','cc']a.reverse()print a#['cc', 'bb', 'aa']#不能直接print a. ...
- [转]JS私有化的实现——稳妥构造函数
所谓稳妥对象, 指的是没有公共属性, 而且其方法也不引用this的对象.稳妥对象函数遵循与寄生构造函数类似的模式, 但有两点不同: 一是新创建对象的实例方法不引用this: 二是不使用new操作符调用 ...
- 定时任务 linux crontab 学习整理
1. 定时任务命令概念 crontab命令用于设置周期性被执行的指令.即设定脚本 按照规定时间执行相关的操作. 2.定时任务书写规范 * * * ...
- 缓存 memcache 小白笔记
W: Memcached是神魔? Q:Memcached是一个自由开源的,高性能,分布式内存对象缓存系统. W:原理图 Q:如下 1浏览器 2 服务器 3 数据库 4 memcac ...
- chrome编辑器与截图
在地址栏中输入 data:text/html,<html contenteditable>即可使用编辑功能,打开控制台,ctrl + shift + p 调用命令面板,输入 capture ...
- XX出行项目子系统-统计系统设计(定时器项目设计例子)
一. 引言 目前开发的XX出行系统,需要开发数据统计功能,鉴于约约出行系统已经在运营,并且有新版本的迭代,方便以后下个版本复用,遂新建一个子系统. 二. 架构设计 三. 具体实现 1.MySql数据库 ...
- crt0.S(_main)代码分析
crt0,S(_main)代码分析 --- 1. 设置sp寄存器地址 //设置SP栈指针 #if defined(CONFIG_SPL_BUILD) && defined(CONFIG ...