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 不认识 ...
随机推荐
- 【Python】多线程
import threading import time class myThread (threading.Thread): #继承父类threading.Thread def __init__(s ...
- LeetCode题解之Climbing Stairs
1.题目描述 2.问题分析 使用动态规划. 3.代码 int climbStairs(int n) { ){ return n; } ]; dp[] = ; dp[] = ; dp[] = ; ; i ...
- 域名检索&路由算法
域名查询顺序: a. 浏览器缓存(本机hosts文件),浏览器会缓存DNS记录一段时间. b. 系统缓存 c. 路由器缓存 d. 检查ISP e. 递归搜索域名服务器 路由算法: 一.静态路由算法 a ...
- Mariadb配置Galera集群
一.增加MariaDB源 cd /etc/yum.repos.d vi MariaDB.repo # MariaDB 10.1 CentOS repository list - created 201 ...
- MySQL优化—工欲善其事,必先利其器(2)
上一篇文章简单介绍了下EXPLAIN的用法,今天主要介绍以下几点内容: 慢查询日志 打开慢查询日志 保存慢查询日志到表中 慢查询日志分析 Percona Toolkit介绍 安装 pt-query-d ...
- Docker容器学习与分享11
容器的数据存储 容器在删除之后,里面所有的数据都会丢失,如果其他程序需要用到某一部分的数据那就没办法了. 所以可以将容器内的数据存储到容器之外,比如存储到宿主机内.(Docker提供了好几种方法) 将 ...
- 粗略的整改一下blog
一.先找个简约的模板:看个人喜好咯 二.页面定制CSS: 1.首先,查看主页源码,了解一下各个标签的id,引用的class等 2.通过操作相应的id,class,和标签,进行个性化.这里需要具备看懂和 ...
- 树莓派3B+ wifi 5G连接
新烧的Raspbian 系统,一开始需要设置wifi的一些配置,其中会选择一个国家(set country),一开始选择的是CN(中国),发现只能连接2.4G的网络,5G的网络连接不上,这很奇怪, 因 ...
- kdTree相关原理及c++实现
kdTree概念 kd-tree或者k维树是计算机科学中使用的一种数据结构,用来组织表示k维空间中点的集合.它是一种带有其他约束条件的二分查找树.Kd-tree对于区间和近邻搜索十分有用.一般位于三维 ...
- 7、Django的模型层(1)
第1节:ORM简介 ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极 ...