Luogu P2055 [ZJOI2009]假期的宿舍
一道网络有关的问题,还是一句话
网络流重在建模!
这里主要讲两种算法。
1.二分图匹配:
分析题意,我们可以知道题目要求是让所有留在学校的人都能有床睡
而 所有留在学校的人=本校不回家的人+外校的人;
床的总量=所有本校生的数量;
理解题意后,我们考虑将所有人的情况拆开来考虑,即:
每个人有两个信息:人和他的床(如果他有的话)
将人编号1~n,那么床就是n+1~2*n(人的编号加上n即为床的编号)
那么只要两人之间有关系,就可以对应的将他们的人和床之间连一条无权值的边
再找到所有留在学校的人分别跑匈牙利算法,看看是否存在最大匹配=所有留在学校的人数
可以根据样例理解一下:
其中红色的表示需要床的人,绿色表示可用的床
注意不要忘记对于不回家的本校生和他自己的床之间连一条边
CODE
#include<cstdio>
#include<cstring>
using namespace std;
const int N=,INF=1e9;
struct edge
{
int to,next;
}e[N*N*];
int head[N*],from[N*],ti,n,i,j,k,x,tot,sum;
bool sch[N*],need[N*],vis[N*];
inline void read(int &x)
{
x=; char ch=getchar();
while (ch<''||ch>'') ch=getchar();
while (ch>=''&&ch<='') x=x*+ch-'',ch=getchar();
}
inline void add(int x,int y)
{
e[++k].to=y; e[k].next=head[x]; head[x]=k;
}
inline bool find(int now)
{
for (int i=head[now];i!=-;i=e[i].next)
if (!vis[e[i].to]&&sch[e[i].to-n])
{
vis[e[i].to]=;
if (!from[e[i].to]||find(from[e[i].to]))
{
from[e[i].to]=now;
return ;
}
}
return ;
}
int main()
{
read(ti);
while (ti--)
{
memset(e,-,sizeof(e));
memset(head,-,sizeof(head));
memset(sch,,sizeof(sch));
memset(need,,sizeof(need));
memset(from,,sizeof(from));
read(n); k=tot=sum=;
for (i=;i<=n;++i)
{
read(x);
if (x) sch[i]=;
}
for (i=;i<=n;++i)
{
read(x);
if (sch[i]&&!x) need[i]=,add(i,i+n),++tot;
if (!sch[i]) need[i]=,++tot;
}
for (i=;i<=n;++i)
for (j=;j<=n;++j)
{
read(x);
if (x) add(i,j+n);
}
for (i=;i<=n;++i)
if (need[i])
{
memset(vis,,sizeof(vis));
sum+=find(i);
}
puts(sum==tot?"^_^":"T_T");
}
return ;
}
2.最大流
和上面的算法很类似,就是设置一个超级源点S,一个超级汇点T
由S向所有需要的人连一条边,所有可用的床向T连一条边,然后跑S到T最大流即可
思路和上面类似
CODE
#include<cstdio>
#include<cstring>
using namespace std;
const int N=,INF=1e9;
struct edge
{
int to,next,c;
}e[N*N*];
int head[N*],dep[N*],q[N*],ti,n,i,j,k,x,s,t,tot;
bool h[N*];
inline void read(int &x)
{
x=; char ch=getchar();
while (ch<''||ch>'') ch=getchar();
while (ch>=''&&ch<='') x=x*+ch-'',ch=getchar();
}
inline void add(int x,int y,int z)
{
e[++k].to=y; e[k].c=z; e[k].next=head[x]; head[x]=k;
}
inline int min(int a,int b)
{
return a<b?a:b;
}
inline bool BFS()
{
memset(dep,,sizeof(dep));
dep[s]=; q[]=s;
int H=,T=;
while (H<T)
{
int now=q[++H];
for (int i=head[now];i!=-;i=e[i].next)
if (!dep[e[i].to]&&e[i].c)
{
dep[e[i].to]=dep[now]+;
q[++T]=e[i].to;
}
}
return dep[t];
}
inline int DFS(int now,int dist)
{
if (now==t) return dist;
int res=;
for (int i=head[now];i!=-&&dist;i=e[i].next)
if (dep[e[i].to]==dep[now]+&&e[i].c)
{
int dis=DFS(e[i].to,min(dist,e[i].c));
dist-=dis; res+=dis;
e[i].c-=dis; e[i^].c+=dis;
}
if (!res) dep[now]=;
return res;
}
inline int Dinic()
{
int sum=;
while (BFS()) sum+=DFS(s,INF);
return sum;
}
int main()
{
read(ti);
while (ti--)
{
memset(e,-,sizeof(e));
memset(head,-,sizeof(head));
memset(h,,sizeof(h));
read(n); k=-; s=tot=; t=*n+;
for (i=;i<=n;++i)
{
read(x);
if (x) add(i+n,t,),add(t,i+n,),h[i]=;
}
for (i=;i<=n;++i)
{
read(x);
if (!h[i]||(h[i]&&!x)) add(s,i,),add(i,s,),++tot;
}
for (i=;i<=n;++i)
for (j=;j<=n;++j)
{
read(x);
if (x||i==j) add(i,j+n,),add(j+n,i,);
}
if (Dinic()==tot) puts("^_^"); else puts("T_T");
}
return ;
}
Luogu P2055 [ZJOI2009]假期的宿舍的更多相关文章
- BZOJ 1433 && Luogu P2055 [ZJOI2009]假期的宿舍 匈牙利算法
刚学了匈牙利正好练练手(我不会说一开始我写错了)(怕不是寒假就讲了可是我不会) 把人看做左部点,床看作右部点 建图:(!!在校相当于有床,不在校相当于没有床 但是要来学校) 1.在校的 不走的人 自己 ...
- 洛谷P2055 [ZJOI2009]假期的宿舍
P2055 [ZJOI2009]假期的宿舍 题目描述 学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题.比如 A 和 B 都是学校的学生,A ...
- 洛谷——P2055 [ZJOI2009]假期的宿舍
P2055 [ZJOI2009]假期的宿舍 学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题.比如 A 和 B 都是学校的学生,A 要回家,而 ...
- P2055 [ZJOI2009]假期的宿舍 题解(二分图)
题目链接 P2055 [ZJOI2009]假期的宿舍 解题思路 因为懒,提供一种不连边,直接根据题目给出的邻接矩阵进行匈牙利算法的思路. \(a[i][j]\)表示\(i\)能不能睡\(j\)的床,需 ...
- 洛谷P2055 [ZJOI2009]假期的宿舍 题解
题目链接: https://www.luogu.org/problemnew/show/P2055 分析: 这道题比较简单,二分图的练习题(当然最大流同理). 易得我们可以将人放在一侧,床放在一侧. ...
- 洛谷 P2055 [ZJOI2009]假期的宿舍
洛谷 P2055 题目描述 学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题.比如 A 和 B 都是学校的学生,A 要回家,而 C 来看B,C ...
- 洛谷P2055 [ZJOI2009]假期的宿舍 [二分图最大匹配]
题目描述 学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题.比如 A 和 B 都是学校的学生,A 要回家,而 C 来看B,C 与 A 不认识. ...
- P2055 [ZJOI2009]假期的宿舍
思路 看到复杂的匹配条件,发现要让一个人和一个床匹配,所以就每个有床的人(指本校学生)和t连一条边,每个需要床的人(指外校的人和不回家的人)和s连一条边,i和j互相认识就把i和j的床连在一起,自己和自 ...
- P2055 [ZJOI2009]假期的宿舍[二分图匹配]
题目描述 学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题. 比如 A 和 B 都是学校的学生,A 要回家,而 C 来看B,C 与 A 不认识 ...
随机推荐
- ionic开发之Android的focus起作用,而iOS不起作用
基于ionic的iOS的hybird APP无法使用focus获取焦点和键盘的问题. 解决办法就是: 原本APP的配置文件config.xml里面默认有一句 这句话的大概意思就是键盘的显示需要用户去触 ...
- Python+Selenium笔记(七):WebDriver和WebElement
(一) WebDriver WebDriver提供许多用来与浏览器交互的功能和设置,通过WebDriver的功能和一些方法,来实现与浏览器窗口.警告.框架和弹出窗口的交互,它也提供了自动化操作浏览器 ...
- SQL Server 跨网段(跨机房)通过备份文件初始化复制
笔者最近碰到了需要搭建跨网段的SQL Server复制,实际的拓扑结构如下草图所示: 发布端A服务器位于CDC机房中 订阅端B服务器位于阿里云 因为SQL Server复制不支持通过IP连接分发服务器 ...
- 简单实现MySQL数据库的日志审计
时间 2018-12-23 08:01:11 FreeBuf 原文 https://www.freebuf.com/articles/es/192062.html 主题 MySQL 0×0 背景 ...
- 从零起步做到Linux运维经理,你必须管好的23个细节
不想成为将军的士兵,不是好士兵-拿破仑 如何成为运维经理?成为运维经理需要什么样的能力?我想很多运维工程师都会有这样的思考和问题. 如何成为运维经理.一般来说,运维经理大概有两种出身,一种是从底层最基 ...
- 大数据开发实战:HDFS和MapReduce优缺点分析
一. HDFS和MapReduce优缺点 1.HDFS的优势 HDFS的英文全称是 Hadoop Distributed File System,即Hadoop分布式文件系统,它是Hadoop的核心子 ...
- ZooKeeper 数据结构 & 命令
0. 说明 记录 ZooKeeper 数据结构 & 命令 1. ZooKeeper 数据结构 ZooKeeper 特性: ZooKeeper 文件系统以 / 为根目录,文件系统为树形结构,每 ...
- Shell学习---Shell脚本的静态检查工具shellcheck
Shell脚本的静态检查工具shellcheck ubuntu下 apt install shellcheck ,即可安装shellcheck.写完shell脚本,记得用它检查一下,能给你点建议的.要 ...
- MySQL C API 访问 MySQL 示例
代码: /* Simple C program that connects to MySQL Database server */ #include <mysql.h> #include ...
- python2.7 threading RLock/Condition文档翻译 (RLock/Condition详解)
RLock Objects 可重入锁是一个同步原语,它可以被同一个线程多次获取.在内部,除了原始锁使用的锁定/解锁状态之外,它还使用“线程拥有”和“递归级别”的概念.在锁定状态下,某些线程拥有锁:在未 ...