洛谷 P2055

题目描述

学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题。比如 A 和 B 都是学校的学生,A 要回家,而 C 来看B,C 与 A 不认识。我们假设每个人只能睡和自己直接认识的人的床。那么一个解决方案就是 B 睡 A 的床而 C 睡 B 的床。而实际情况可能非常复杂,有的人可能认识好多在校学生,在校学生之间也不一定都互相认识。我们已知一共有 n 个人,并且知道其中每个人是不是本校学生,也知道每个本校学生是否回家。问是否存在一个方案使得所有不回家的本校学生和来看他们的其他人都有地方住。

输入输出格式

输入格式:

第一行一个数 T 表示数据组数。接下来 T 组数据,每组数据第一行一个数n 表示涉及到的总人数。接下来一行 n 个数,第 i
个数表示第 i 个人是否是在校学生 (0 表示不是,1 表示是)。再接下来一行 n 个数,第 i 个数表示第 i 个人是否回家 (0
表示不会家,1 表示回家,注意如果第 i 个人不是在校学生,那么这个位置上的数是一个随机的数,你应该在读入以后忽略它)。接下来 n 行每行 n
个数,第 i 行第 j 个数表示 i 和 j 是否认识 (1 表示认识,0 表示不认识,第 i 行 i 个的值为
0,但是显然自己还是可以睡自己的床),认识的关系是相互的。

输出格式:

对于每组数据,如果存在一个方案则输出 “ ^_^ ”(不含引号) 否则输出“T_T”(不含引号)。(注意输出的都是半角字符,即三个符号的 ASCII 码分别为94,84,95)

输入输出样例

输入样例#1:

  1. 1
  2. 3
  3. 1 1 0
  4. 0 1 0
  5. 0 1 1
  6. 1 0 0
  7. 1 0 0
输出样例#1:

  1. ^_^

说明

对于 30% 的数据满足 1 ≤ n ≤ 12。

对于 100% 的数据满足 1 ≤ n ≤ 50,1 ≤ T ≤ 20。

多组数据!!!

Solution:

这道题一看就类似于二分图匹配的问题,既可以用匈牙利算法来做也可以用最大流做。

1、用匈牙利算法。思路就是把每个是学校里的学生和他们自己的床位相连且边权为1(实际实现时可以都连,只需要在增广时判断就行了),再统计需要在学校住的同学的人数(因为只有这些人需要床位),然后把相互认识的人和床位相连且边权为1(实际实现时这里也可以不必判断是否是学校的学生,只需要增广时特判就行了)。。。关键的增广时,记得判断:必须是留在学校的学生或者外来的学生,才能以他为起点进行增广。最后若增广累加的值等于一开始统计的需要在学校住的人数,则可以,否则不行。

代码:

  1. #include<bits/stdc++.h>
  2. #define il inline
  3. using namespace std;
  4. const int N=,inf=;
  5. int T,n,l[N],k[N],cnt,pre[N],ans,tot,h[N];
  6. bool vis[N];
  7. struct edge{
  8. int to,net;
  9. }e[N*];
  10. il void add(int u,int v)
  11. {
  12. e[++cnt].to=v,e[cnt].net=h[u],h[u]=cnt;
  13. }
  14. il bool find(int u)
  15. {
  16. for(int i=h[u];i;i=e[i].net){
  17. int v=e[i].to;
  18. if(!vis[v]){
  19. vis[v]=;
  20. if(!pre[v]||find(pre[v])){pre[v]=u;return ;}
  21. }
  22. }
  23. return ;
  24. }
  25. int main()
  26. {
  27. scanf("%d",&T);
  28. while(T--)
  29. {
  30. scanf("%d",&n);
  31. ans=tot=;cnt=;
  32. memset(h,,sizeof(h));
  33. memset(pre,,sizeof(pre));
  34. for(int i=;i<=n;i++)scanf("%d",&l[i]);
  35. for(int i=;i<=n;i++){
  36. scanf("%d",&k[i]);
  37. if(l[i]&&!k[i])add(i,i+n);
  38. }
  39. for(int i=;i<=n;i++)
  40. if(!l[i]||(l[i]&&!k[i]))tot++;
  41. int x;
  42. for(int i=;i<=n;i++)
  43. for(int j=;j<=n;j++){
  44. scanf("%d",&x);
  45. if(x&&l[j])add(i,j+n);
  46. }
  47. for(int i=;i<=n;i++)
  48. if(!l[i]||(l[i]&&!k[i])){
  49. memset(vis,,sizeof(vis));
  50. if(find(i))ans++;}
  51. // printf("%d %d\n",ans,tot);
  52. if(ans==tot)printf("^_^\n");
  53. else printf("T_T\n");
  54. }
  55. return ;
  56. }

2、用最大流做。思路与匈牙利算法的类似,但是附加源点S(连向需要住校的人并赋权值为1)和汇点T(由每个床位连向T并赋权值为1),然后与匈牙利算法相同,统计需要住校的人数,加边时注意必须是需要住校的且认识的才能与床位相连(该回家的肯定是回家好,这样不占床位),最后增广累加答案,若等于需要住校的人数则可以,否则不行。

代码:

  1. #include<bits/stdc++.h>
  2. #define il inline
  3. using namespace std;
  4. const int N=,inf=;
  5. int T,n,s,t=,l[N],k[N],cnt=,dis[N],h[N],ans,tot;
  6. queue<int>q;
  7. struct edge{
  8. int to,net,v;
  9. }e[N*];
  10. il void add(int u,int v,int w)
  11. {
  12. e[++cnt].to=v,e[cnt].v=w,e[cnt].net=h[u],h[u]=cnt;
  13. e[++cnt].to=u,e[cnt].v=,e[cnt].net=h[v],h[v]=cnt;
  14. }
  15. il bool bfs()
  16. {
  17. memset(dis,-,sizeof(dis));
  18. q.push(s),dis[s]=;
  19. while(!q.empty())
  20. {
  21. int u=q.front();q.pop();
  22. for(int i=h[u];i;i=e[i].net)
  23. if(dis[e[i].to]==-&&e[i].v>)dis[e[i].to]=dis[u]+,q.push(e[i].to);
  24. }
  25. return dis[t]!=-;
  26. }
  27. il int dfs(int u,int op)
  28. {
  29. if(u==t)return op;
  30. int flow=,used=;
  31. for(int i=h[u];i;i=e[i].net)
  32. {
  33. int v=e[i].to;
  34. if(dis[v]==dis[u]+&&e[i].v>)
  35. {
  36. used=dfs(v,min(op,e[i].v));
  37. if(!used)continue;
  38. flow+=used,op-=used;
  39. e[i].v-=used,e[i^].v+=used;
  40. if(!op)break;
  41. }
  42. }
  43. if(!flow)dis[u]==-;
  44. return flow;
  45. }
  46. int main()
  47. {
  48. scanf("%d",&T);
  49. while(T--)
  50. {
  51. scanf("%d",&n);
  52. for(int i=;i<=N;i++)h[i]=,l[i]=,k[i]=;
  53. //memset(e,0,sizeof(e));
  54. cnt=;ans=tot=;
  55. int x;
  56. for(int i=;i<=n;i++)scanf("%d",&l[i]);
  57. for(int i=;i<=n;i++){
  58. scanf("%d",&x);
  59. if(l[i]==)k[i]=x;
  60. }
  61. for(int i=;i<=n;i++){
  62. if(!k[i])add(s,i,),tot++;
  63. if(l[i])add(i+n,t,);
  64. }
  65. for(int i=;i<=n;i++)
  66. for(int j=;j<=n;j++){
  67. scanf("%d",&x);
  68. if(x==||i==j)add(i,j+n,);
  69. }
  70. while(bfs())ans+=dfs(s,inf);
  71. if(ans==tot)printf("^_^\n");
  72. else printf("T_T\n");
  73. }
  74. return ;
  75. }

洛谷 P2055 [ZJOI2009]假期的宿舍的更多相关文章

  1. 洛谷P2055 [ZJOI2009]假期的宿舍

    P2055 [ZJOI2009]假期的宿舍 题目描述 学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题.比如 A 和 B 都是学校的学生,A ...

  2. 洛谷——P2055 [ZJOI2009]假期的宿舍

    P2055 [ZJOI2009]假期的宿舍 学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题.比如 A 和 B 都是学校的学生,A 要回家,而 ...

  3. 洛谷P2055 [ZJOI2009]假期的宿舍 题解

    题目链接: https://www.luogu.org/problemnew/show/P2055 分析: 这道题比较简单,二分图的练习题(当然最大流同理). 易得我们可以将人放在一侧,床放在一侧. ...

  4. 洛谷P2055 [ZJOI2009]假期的宿舍 [二分图最大匹配]

    题目描述 学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题.比如 A 和 B 都是学校的学生,A 要回家,而 C 来看B,C 与 A 不认识. ...

  5. 洛谷$P2055\ [ZJOI2009]$ 假期的宿舍 最大流

    正解:最大流 解题报告: 传送门$QwQ$ 这种一看就很网络流鸭,直接说咋建图趴. 考虑把在校的人拆成人和床.$S$连向所有不回家的人,所有床连向$T$,认识的人之间人向床连边,跑个最大流就成. $o ...

  6. 洛谷 P2055 【假期的宿舍】

    题库 :洛谷 题号 :2055 题目 :假期的宿舍 link :https://www.luogu.org/problem/P2055 首先明确一下:校内的每个学生都有一张床(只是校内的有) 思路 : ...

  7. BZOJ1433或洛谷2055 [ZJOI2009]假期的宿舍

    BZOJ原题链接 洛谷原题链接 对于每个需要床位的人向他能睡的床连边,然后就是二分图最大匹配模板了. 这里用匈牙利算法. #include<cstdio> #include<cstr ...

  8. 洛谷2055 [ZJOI2009]假期的宿舍

    题目描述 学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题.比如 A 和 B 都是学校的学生,A 要回家,而 C 来看B,C 与 A 不认识. ...

  9. 洛谷 2055 [ZJOI2009]假期的宿舍——二分图匹配

    题目:https://www.luogu.org/problemnew/show/P2055 #include<iostream> #include<cstdio> #incl ...

随机推荐

  1. pyhon3.0 day01 变量、输入、输出、循环

    pyhon3.0 基础01 1 python解释器 Python的解释器很多,但使用最广泛的还是CPython.如果要和Java或.Net平台交互,最好的办法不是用Jython或IronPython, ...

  2. NumPy v1.15手册汉化

    NumPy参考 数组创建 零 和 一 empty(shape[, dtype, order]):返回给定形状和类型的新数组,而不初始化条目 empty_like(prototype[, dtype,  ...

  3. linux、WINDOWS命令行下查找和统计行数

    linux : 例子: netstat -an | grep TIME_WAIT | wc -l |  管道符 grep 查找命令 wc 统计命令 windows: 例子: netstat -an | ...

  4. Qt 链接报错 version `Qt_5' not found

    问题: 在Ubuntu 上发布软件包的时候,复制链接库的时候出现Qt 版本找不到的情况: ./libqxcb.so: /usr/lib/x86_64-linux-gnu/libQt5XcbQpa.so ...

  5. 《算法图解》——第十章 K最近邻算法

    第十章    K最近邻算法 1 K最近邻(k-nearest neighbours,KNN)——水果分类 2 创建推荐系统 利用相似的用户相距较近,但如何确定两位用户的相似程度呢? ①特征抽取 对水果 ...

  6. Linux下文件的打包、解压缩指令——tar,gzip,bzip2

    本文是对 鸟叔的Linux私房菜(基础学习篇) 第三版 的学习笔记,原文可参考原书中文网站 鸟叔的Linux私房菜.更多详细信息可直接参考对应Linux命令的 man 帮助( 如 man tar). ...

  7. eclipse版本信息及操作系统

    一.查看版本信息: 进入到eclipse安装目录下,有一个.eclipseproduct文件,用记事本打开,就可以知道版本了,后面version=的值就是版本 二.是否为32位操作系统: 找到ecli ...

  8. 爬虫:Scrapy12 - Stats Collection

    Scrapy 提供了方便的收集数据的机制.数据以 key/value 方式存储,值大多是计数值.该机制叫做数据收集器(Stats Collector),可以通过 Crawler API 的属性 sta ...

  9. C++的反思与总结

    博客作业学到的东西: 1.博客作业应该说是从寒假就开始了,因为博客作业,所以我寒假时都不敢玩得太疯狂,毕竟还有博客作业没做呢.有了博客作业,我就从一个连博客是什么都不知道无知少年,开始去了解博客是什么 ...

  10. jdbc 6.0

    1.获取数据库自动生成的键值 package com.rong.jielong; import java.sql.Connection; import java.sql.DriverManager; ...