题目链接:HDU  4635

题目大意:

给你一个有向图,加有向边,使得这个图是简单有向图。问你最多加多少条有向边。

简单有向图:

1、不存在有向重边。

2、不存在图循环。(注意是不存在 “图” 循环,就是不能使整个图成为 “强连通图” 。意思是可以存在环,但不能是全图循环。同样,两个点之间可以有两条相反有向边。)

分析:

1、如果我要加最多的边,全图仍然不为 “强连通图” 。那么最多的情况就是,有两个巨大的环,他们之前有且仅有一条有向边。故先进行 “有向图缩点” ,先从 小环 开始分析。

2、加边加到最后,一定存在仅剩的两个超级点 X 与 Y ,且 X 与 Y 之间有且仅有一条有向边。这样可以使得 X Y 分处两个最大环。

3、缩点加边到最后,X 与 Y 一定是 X → Y 或者 Y → X 的,所以作为 X Y 的前提条件是, 入度为 0 或者出度为 0 。(重点)

4、其次,X 与 Y 是两个最大有向环,那么我们可以使 X 或 Y 变成完全图,就可以继续加边而且不会导致全图变成 “强连通图” ,因为 X 与 Y 中间始终仅有一条有向边。

5、假设 X Y 之间有 : X → Y ,则我使 X 中的所有节点 ,全部以 → 有向边连接 Y 中的所有节点,也不会使得全图变为 “强连通图” ,故我还可以这样加边。(注意,连的边一定要与 X 到 Y 之间的有向边同向,否则就变成环了)

通过以上分析我们可以知道思路:

假设 X 的节点数为 x ,Y 的节点数为 y 。

1、以 X 为完全图时,X 中的有向边数最多为: x * (x - 1)

2、以 Y 为完全图时,Y 中的有向边数最多为: y * (y - 1)

3、X 中的全部节点以同一种有向边连接 Y 的全部节点,边数: x * y

4、由于给了 m 条边,故只需要加 x * (x - 1)+ y * (y - 1)+ x * y - m 条边即可。

将上面的 x * (x - 1)+ y * (y - 1)+ x * y - m x + y = n 联立得:

加的边数为:n2 - x * y - n - m

故我们只需要使 x * y 最小即可。而由于 x + y = n ,是定值,所以 x * y 的最小值即 x 的最小值 乘以 y (y = n - x) 。

由于 X 与 Y 是入度或出度为 0 的点,故只要找出这类缩点后的超级点中,点的个数最小的作为 X 点,X 自身成为完全图,不需要加别的点。然后剩下的所有点与 Y 点一同成为完全图即可。这要就可以保证 x 最小了。

代码如下:

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<string.h>
  4. #include<queue>
  5. #define maxn 100008
  6. using namespace std;
  7. typedef long long ll;
  8. int cnt, Index, tot, sum;
  9. int head[maxn], low[maxn], dfn[maxn], q[maxn];
  10. int in[maxn],out[maxn];
  11. int qhead[maxn];
  12. bool vis[maxn];
  13. int pre[maxn];
  14. ll ans[maxn],n,m;
  15. struct Edge
  16. {
  17. int to;
  18. int next;
  19. }edge[maxn << ];
  20. inline void add(int u, int v)
  21. {
  22. edge[++cnt].to = v;
  23. edge[cnt].next = head[u];
  24. head[u] = cnt;
  25. return;
  26. }
  27. inline void tarjan(int u)
  28. {
  29. low[u] = dfn[u] = ++Index;
  30. q[++tot] = u;
  31. vis[u] = true;
  32. for (int i = head[u]; i; i = edge[i].next)
  33. {
  34. int v = edge[i].to;
  35. if (!dfn[v]) {
  36. tarjan(v);
  37. low[u] = min(low[u], low[v]);
  38. }
  39. else if (vis[v]) low[u] = min(low[u], dfn[v]);
  40. }
  41. if (low[u] == dfn[u])
  42. {
  43. ++sum;
  44. do {
  45. ans[sum]++;
  46. pre[q[tot]] = sum;
  47. vis[q[tot--]] = false;
  48. } while (q[tot + ] != u);
  49. }
  50. return;
  51. }
  52. void init()
  53. {
  54. cnt=Index=tot=sum=;
  55. for(int i=;i<=n;i++) dfn[i]=vis[i]=head[i]=qhead[i]=ans[i]=in[i]=out[i]=;
  56. memset(edge,,sizeof(edge));
  57. return;
  58. }
  59. int main()
  60. {
  61. int t;
  62. scanf("%d",&t);
  63. int T=;
  64. while(t--){
  65. init();
  66. scanf("%lld%lld", &n, &m);
  67. int A, B;
  68. for (int i = ; i <= m; i++) {
  69. scanf("%d%d", &A, &B);
  70. add(A, B);
  71. }
  72. for (int i = ; i <= n; i++) {
  73. if (!dfn[i]) tarjan(i);
  74. }
  75. if(sum==){ printf("Case %d: -1\n",++T ); continue;}
  76. cnt = ;
  77. for (int i = ; i <= n; i++) {
  78. for (int j = head[i]; j; j = edge[j].next) {
  79. int v = edge[j].to;
  80. if (pre[i] != pre[v]){
  81. in[pre[v]]++,out[pre[i]]++;
  82. }
  83. }
  84. }
  85. ll res=0x3f3f3f3f;
  86. for(int i=;i<=sum;i++){
  87. if(in[i]==||out[i]==){
  88. res=min(res,ans[i]);
  89. }
  90. }
  91. res=1ll*n*n-n-m-res*(n-res);
  92. printf("Case %d: %lld\n",++T,res );
  93. }
  94. }

HDU 4635 (完全图 和 有向图缩点)的更多相关文章

  1. hdu 4635 Strongly connected 强连通缩点

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4635 题意:给你一个n个点m条边的图,问在图不是强连通图的情况下,最多可以向图中添多少条边,若图为原来 ...

  2. Strongly connected HDU - 4635(判断强连通图 缩点)

    找出强联通块,计算每个连通块内的点数.将点数最少的那个连通块单独拿出来,其余的连通块合并成一个连通分量. 那么假设第一个连通块的 点数是 x  第二个连通块的点数是 y 一个强连通图(每两个点之间,至 ...

  3. hdu 3072 有向图缩点成最小树形图计算最小权

    题意,从0点出发,遍历所有点,遍历边时候要付出代价,在一个SCC中的边不要付费.求最小费用. 有向图缩点(无需建立新图,,n<=50000,建则超时),遍历边,若不在一个SCC中,用一个数组更新 ...

  4. hdu 1827 有向图缩点看度数

    题意:给一个有向图,选最少的点(同时最小价值),从这些点出发可以遍历所有. 思路:先有向图缩点,成有向树,找入度为0的点即可. 下面给出有向图缩点方法: 用一个数组SCC记录即可,重新编号,1.... ...

  5. HDU 4635 —— Strongly connected——————【 强连通、最多加多少边仍不强连通】

    Strongly connected Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u ...

  6. HDU 4635 Strongly connected (强连通分量)

    题意 给定一个N个点M条边的简单图,求最多能加几条边,使得这个图仍然不是一个强连通图. 思路 2013多校第四场1004题.和官方题解思路一样,就直接贴了~ 最终添加完边的图,肯定可以分成两个部X和Y ...

  7. HDU 4635 - Strongly connected(2013MUTC4-1004)(强连通分量)

    t这道题在我们队属于我的范畴,最终因为最后一个环节想错了,也没搞出来 题解是这么说的: 最终添加完边的图,肯定可以分成两个部X和Y,其中只有X到Y的边没有Y到X的边,那么要使得边数尽可能的多,则X部肯 ...

  8. hdu 4635 Strongly connected(Tarjan)

    做完后,看了解题报告,思路是一样的.我就直接粘过来吧 最终添加完边的图,肯定可以分成两个部X和Y,其中只有X到Y的边没有Y到X的边,那么要使得边数尽可能的多,则X部肯定是一个完全图,Y部也是,同时X部 ...

  9. HDU 4635 Strongly connected (Tarjan+一点数学分析)

    Strongly connected Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) ...

随机推荐

  1. 从零开始实现放置游戏(十)——实现战斗挂机(1)hessian服务端搭建

    前面实现RMS系统时,我们让其直接访问底层数据库.后面我们在idlewow-game模块实现游戏逻辑时,将不再直接访问底层数据,而是通过hessian服务暴露接口给表现层. 本章,我们先把hessia ...

  2. WordPress教程之如何入门WordPress

    这篇文章将介绍如何设置 WordPress,并自定义其基本功能.WordPress 的安装包相对较小(低于 10 MB),非常易于安装和管理.为了托管自己的网站,你可以获得几个不同的选项. 你可以通过 ...

  3. SpringCloud解析之Eureka

    本文基于Spring Cloud Edgware.SR6版本,从功能和架构上解析Eureka,让大家对Eureka有一个较为清晰的认识(本文默认大家对分布式微服务有一个初步的概念和理解,本文不涉及或少 ...

  4. Golang 受欢迎的原因:大道至简

    前言 Golang自2009年发布第一个版本,2012年发布1.0版本.在这10年的时间里,不断有开发者加入Golang的阵营中,不断共建Golang生态.其中比较有代表性的Golang编写软件作品是 ...

  5. U盘被写保护大全解

    相信大家的U盘在使用的过程中多或少都有出现过一些问题,写保护,程序写蹦而造成的逻辑错误,或者在使用过程中因电脑而中毒,内部零件损伤等等各种各样倒霉的错误. 简单了解一下是个什么东西吧.U盘写保护其实就 ...

  6. KdTree && Octree 原理学习对比以及可视化分析--"索引树"

    1. Kdtree 原理 k-d树(k-dimensional树的简称),是一种分割k维数据空间的数据结构.主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索): 索引结构中相似性查询有两种基 ...

  7. [JavaWeb] Ubuntu下载eclipse for ee

    进入网站进行下载 https://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/2019- ...

  8. 个人永久性免费-Excel催化剂插件功能修复与更新汇总篇之九

    第11波-快速批量插入图片并保护纵横比不变 原文链接:https://www.jianshu.com/p/9a3d9aa7ba7e 修复了插入图片有纵向的图片时,插入后还是显示横向的情况. 第83波- ...

  9. 个人永久性免费-Excel催化剂功能第62波-单元格区域内数据加解密处理,最有效地保护数据方式

    Excel的数据保护能力有限,诸如之前提及过的工作表保护.工作薄保护等,都是十分微弱的保护措施,而对于强保护的工作薄打开密码来说,它像是个总开关一样,要么全不能看,要么就全看到.有这样的场景需求,一份 ...

  10. Excel催化剂开源第11波-动态数组函数技术开源及要点讲述

    在Excel催化剂中,大量的自定义函数使用了动态数组函数效果,虽然不是原生的Excel365版效果(听说Excel2019版取消了支持动态数组函数,还没求证到位,Excel365是可以用,但也仅限于部 ...