【Vijos1022]】Victoria的舞会2

Description

Victoria是一位颇有成就的艺术家,他因油画作品《我爱北京天安门》闻名于世界。现在,他为了报答帮助他的同行们,准备开一个舞会。 

Victoria准备邀请n个已经确定的人,可是问题来了: 

这n个人每一个人都有一个小花名册,名册里面写着他所愿意交流的人的名字。比如说在A的人名单里写了B,那么表示A愿意与B交流;但是B的名单里不见的有A,也就是说B不见的想与A交流。但是如果A愿意与B交流,B愿意与C交流,那么A一定愿意与C交流。也就是说交流有传递性。 

Victoria觉得需要将这n个人分为m组,要求每一组的任何一人都愿意与组内其他人交流。并求出一种方案以确定m的最小值是多少。 

注意:自己的名单里面不会有自己的名字。

Input

第一行一个数n。 

接下来n行,每i+1行表示编号为i的人的小花名册名单,名单以0结束。1<=n<=200。

Output

一个数,m。

Sample Input

18 



18 0 





11 0 











5 0 













2 0

Sample Output

16

问题分析:

问题描述简要概括为:给出舞会成员之间的关系图(有向图),求解有向图的强连通分量数量。

解法1:

图的连通性+并查集:首先求出任意两点之间的连通性(最短路径),然后将互相连通的顶点使用并查集合并,并统计合并的堆数,即为所求解。

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<algorithm>
  4. #include<iostream>
  5. /* 本题可以构建一个人与人之间的关系图(有向图),问题转化为求解有向连通图的极大连通子块的数量
  6. 求解过程:
  7. 第一步,构建有向连通图,并使用Floyd求出各点之间的连通性(顶点数量较少)
  8. 第二步,若两点之间互相连通,则把这两个点绑定到一块(分组计数减1),可以使用并查集将两个互相连通的顶点合并
  9. */
  10. using namespace std;
  11. #define Max 10000
  12. int people[205][205],Link[205][205],father[205]; //people[][]存储每人的花名册,link[][]存储相互之间的连通性
  13. int n,t,temp,ans;
  14.  
  15. int Find(int i)
  16. {
  17. if(i==father[i]) return i;
  18. return Find(father[i]);
  19. }
  20.  
  21. void Merge(int a,int b)
  22. {
  23. a=Find(a);
  24. b=Find(b);
  25. if(a!=b)
  26. {
  27. father[b]=a;
  28. }
  29. }
  30.  
  31. void Floyd()
  32. {
  33. for(int i=1;i<=n;i++)
  34. for(int j=1;j<=n;j++)
  35. for(int k=1;k<=n;k++)
  36. {
  37. if(i!=j||i!=k||j!=k)
  38. {
  39. Link[i][j]=min(Link[i][j],Link[i][k]+Link[k][j]);
  40. }
  41. }
  42. }
  43.  
  44. int main()
  45. {
  46. ios::sync_with_stdio(false);
  47. freopen("victoria2.in","r",stdin);
  48. freopen("victoria2.out","w",stdout);
  49. cin>>n;
  50. for(int i=1;i<=n;++i)
  51. for(int j=1;j<=n;++j)
  52. {
  53. if(i!=j) Link[i][j]=Max;
  54. }
  55. t=1,ans=n;
  56. while(t<=n)
  57. {
  58. while(cin>>temp)
  59. {
  60. if(temp==0) break;
  61. int seq=++people[t][0];
  62. people[t][seq]=temp;
  63. Link[t][temp]=1;
  64. }
  65. father[t]=t;
  66. ++t;
  67. }
  68. Floyd();
  69. for(int i=1;i<=n;i++)
  70. for(int j=1;j<=n;j++)
  71. {
  72. if(i!=j&&Link[i][j]<Max&&Link[j][i]<Max&&Find(i)!=Find(j)) //并查集合并关系网中互相连通的顶点
  73. {
  74. ans--;
  75. Merge(i,j);
  76. }
  77. }
  78. cout<<ans<<endl;
  79. return 0;
  80. }

解法2:

采用tarjan求有向图的强连通分量,主要使用栈的结构及访问时间戳,Low[ ]数组标记

  1. #include <cstdio>
  2. #include <stack>
  3. #include <algorithm>
  4. #include <vector>
  5. #include <iostream>
  6. using namespace std;
  7.  
  8. vector<int> point[205];
  9. stack<int> S; //栈S用于存储tarja深度搜索过程中顶点的拓扑序列
  10. //InStack[]标记顶点是否在栈中,DFS[]标记顶点的访问时间戳,Low(u)为u或u的子树能追溯到最早的栈中节点次序号
  11. //Belong[]标记顶点属于哪一个强连通分量,index访问时间戳,nun强连通分量计数
  12. int InStack[205]={0},DFS[205],Low[205],Belong[205],Index=0,num=0;
  13.  
  14. void tarjan(int u)
  15. {
  16. DFS[u]=Low[u]=++Index;
  17. S.push(u);
  18. InStack[u]=1;
  19. for(vector<int>::iterator v=point[u].begin();v!=point[u].end();++v)
  20. {
  21. if(!DFS[*v])
  22. {
  23. tarjan(*v);
  24. Low[u]=min(Low[u],Low[*v]);
  25. }
  26. else if(InStack[*v])
  27. {
  28. Low[u]=min(Low[u],DFS[*v]);
  29. }
  30. }
  31. if(DFS[u]==Low[u])
  32. {
  33. int e;
  34. ++num;
  35. while(!S.empty())
  36. {
  37. e=S.top();
  38. S.pop();
  39. InStack[e]=0;
  40. Belong[e]=num;
  41. if(u==e) break;
  42. }
  43. }
  44. }
  45.  
  46. int main()
  47. {
  48. // ios::sync_with_stdio(false); //注意 cin scanf 与cout printf 在关闭同步输入输出流的时候,混合使用会出错
  49. freopen("victoria2.in","r",stdin);
  50. // freopen("victoria2.out","w",stdout);
  51. int n,t,temp;
  52. // scanf("%d",&n);
  53. cin>>n; //这个地方用了cin流读入
  54. t=1;
  55. while(t<=n)
  56. {
  57. while(scanf("%d",&temp)) //这里使用标准scanf()读入,同时存在cin,scanf不能关闭输入输出流同步
  58. {
  59. if(!temp) break;
  60. point[t].push_back(temp);
  61. }
  62. ++t;
  63. }
  64. for(int i=1;i<=n;++i)
  65. {
  66. if(!DFS[i])
  67. {
  68. tarjan(i);
  69. }
  70. }
  71. // printf("%d\n",num);
  72. cout<<num<<endl;
  73. return 0;
  74. }

解法3:

求强连通分量算法Kosaraju,正反图双向搜索,寻找解答树

  1. #include<cstdio>
  2. #include<stack>
  3. #include<cstring>
  4. /*
  5. Kosaraju算法求连通分量,采用正反图双向DFS求连通分量。
  6. 根据:有向图的这样一个性质,一个图和他的transpose graph(边全部反向)具有相同的强连通分量。
  7. 算法求解步骤:
  8. 1.对G求解Reverse Post-Order,即得到顶点的"伪拓扑排序"
  9. 2.对G进行转置得到GR
  10. 3.按照第一步得到的集合中顶点出现的顺序,对GR调用DFS得到若干颗搜索树
  11. 4.每一颗搜索树就代表了一个强连通分量
  12. 这个算法的想法很巧妙,为了突出回向边,对图进行转置,然后对转置的图按照之前得到的顶点(拓扑)序列进行DFS调用。
  13. */
  14. //Map[][]原图关系,rMap[][]反图关系,pcolor[]顶点染色信息,Count连通分量的计数
  15. int Map[205][205],rMap[205][205],pcolor[205]={0},Count=0,N;
  16. std::stack<int> S;
  17.  
  18. void dfs(int u) //正向染色,得到拓扑序列顶点集,存放在栈S
  19. {
  20. pcolor[u]=1;
  21. S.push(u);
  22. for(int v=1;v<=N;++v)
  23. {
  24. if(Map[u][v]==1&&!pcolor[v])
  25. dfs(v);
  26. }
  27. }
  28.  
  29. void rdfs(int u) //反向调用,寻找解的搜索树
  30. {
  31. pcolor[u]=Count; //标记u属于连通分量的标号
  32. for(int v=1;v<=N;++v)
  33. {
  34. if(rMap[u][v]==1&&!pcolor[v])
  35. rdfs(v);
  36. }
  37. }
  38.  
  39. int main()
  40. {
  41. freopen("victoria2.in","r",stdin);
  42. freopen("victoria2.out","w",stdout);
  43. scanf("%d",&N);
  44. int t=1;
  45. while(t<=N)
  46. {
  47. int temp;
  48. while(scanf("%d",&temp))
  49. {
  50. if(temp==0) break;
  51. Map[t][temp]=1;
  52. rMap[temp][t]=1;
  53. }
  54. ++t;
  55. }
  56. for(int i=1;i<=N;++i)
  57. {
  58. if(!pcolor[i]) dfs(i);
  59. }
  60. /*
  61. while(!S.empty())
  62. {
  63. printf("%d ",S.top());
  64. S.pop();
  65. }
  66. printf("\n");
  67. */
  68. memset(pcolor,0,sizeof(pcolor));
  69. while(!S.empty()) //根据正向生成顶点拓扑序列集,进行反向DFS调用,寻找解答搜索树
  70. {
  71. int x=S.top();
  72. S.pop();
  73. if(!pcolor[x])
  74. {
  75. ++Count;
  76. rdfs(x);
  77. }
  78. }
  79. printf("%d\n",Count);
  80. return 0;
  81. }

Victoria的舞会2——图的连通性及连通分量的更多相关文章

  1. 数据结构-图-Java实现:有向图 图存储(邻接矩阵),最小生成树,广度深度遍历,图的连通性,最短路径1

    import java.util.ArrayList; import java.util.List; // 模块E public class AdjMatrixGraph<E> { pro ...

  2. [vijos P1023] Victoria的舞会3

    这… 本来想学习一下Tarjan算法的,没想到码都码好了发现这题不是求强连通分量而是简单的连通分量…图论基础都还给老师了啊啊啊!最后深搜通通解决! v标记是否被访问过,scc标记每个的祖先(本来想写T ...

  3. POJ 2513 - Colored Sticks - [欧拉路][图的连通性][字典树]

    题目链接: http://poj.org/problem?id=2513 http://bailian.openjudge.cn/practice/2513?lang=en_US Time Limit ...

  4. poj 3310(并查集判环,图的连通性,树上最长直径路径标记)

    题目链接:http://poj.org/problem?id=3310 思路:首先是判断图的连通性,以及是否有环存在,这里我们可以用并查集判断,然后就是找2次dfs找树上最长直径了,并且对树上最长直径 ...

  5. POJ2513(字典树+图的连通性判断)

    //用map映射TLE,字典树就AC了#include"cstdio" #include"set" using namespace std; ; ;//26个小 ...

  6. 图的连通性问题的小结 (双连通、2-SAT)

    图的连通性问题包括: 1.强连通分量. 2.最小点基和最小权点基. 3.双连通. 4.全局最小割. 5.2-SAT 一.强连通分量 强连通分量很少单独出题,一般都是把求强连通分量作为缩点工具. 有三种 ...

  7. 2018年牛客多校寒假 第四场 F (call to your teacher) (图的连通性)

    题目链接 传送门:https://ac.nowcoder.com/acm/contest/76/F 思路: 题目的意思就是判断图的连通性可以用可达性矩阵来求,至于图的存储可以用邻接矩阵来储存,求出来可 ...

  8. POJ3177 Redundant Paths 图的边双连通分量

    题目大意:问一个图至少加多少边能使该图的边双连通分量成为它本身. 图的边双连通分量为极大的不存在割边的子图.图的边双连通分量之间由割边连接.求法如下: 求出图的割边 在每个边双连通分量内Dfs,标记每 ...

  9. 算法练习_图的连通性问题(JAVA)

    一.问题 1.问题描述: 有n个点(1...n),输入整数对(8,9),表示8,9点之间存在相互的连接关系. 动态连通性问题--编写一段程序过滤掉所以无意义的整数对,即为在不破坏图连通性的前提下,以最 ...

随机推荐

  1. 目标检测算法之Fast R-CNN算法详解

    在介绍Fast R-CNN之前我们先介绍一下SPP Net 一.SPP Net SPP:Spatial Pyramid Pooling(空间金字塔池化) 众所周知,CNN一般都含有卷积部分和全连接部分 ...

  2. Spring Cloud与Spring Boot版本匹配关系

    Spring Cloud是什么? “Spring Cloud provides tools for developers to quickly build some of the common pat ...

  3. tomcat启动成功但是访问方面都是404

    1.开发环境与错误情况 开发环境是jdk1.7+maven+git+spring MVC+spring+mybatis+mysql. 楼主做小例子的时候发现,tomcat成功启动,但是访问主页,页面提 ...

  4. [转] Shell编程之数组使用

    #!/bin/bash #基本数组操作a=(1 2 3) ##()表示空数组echo "第0个元素:"${a[0]}echo "所有元素: "${a[@]}ec ...

  5. 如何配置使用HTML在线编辑工具

    如何配置使用HTML在线编辑工具 为了更好的.统一的编写统一简单易用的博客,决定采用TinyMCE工具.首先下载TinyMCE4.0包.文件目录如下: 其中, Plugins是插件目录,包括各种插件 ...

  6. Kafka/Zookeeper集群的实现(二)

    [root@kafkazk1 ~]# wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.12/zookeeper-3.4.12. ...

  7. 分布式配置 Spark 2.0版本 2.1版本 1.6版本

    apache的各个软件各个版本下载:  http://archive.apache.org/dist/ 1.下载spark. sudo tar -zxf ~/下载/spark-2.0.2-bin-wi ...

  8. iframe获取元素

    原生js在网页中,父元素获取iframe中的元素: window.onload=function () { 例如: console.log(window.frames["iframe的nam ...

  9. union和union all的区别(面试常考)

    Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序: Union All:对两个结果集进行并集操作,包括重复行,不进行排序: Union因为要进行重复值扫描,所以效率低.如果合 ...

  10. ESP8266进阶篇

    ESP8266进阶篇 20170225(应需要,继续使用此模块!!!) 说一下如何通过内网和外网来控制我的ESP8266的数据模块 1.内网控制:(要求手机直接连接在ESP8266的WIFI上面,使用 ...