题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4635

先判断图是否强连通。如果不是强连通的,那么缩点。

我们的目的是加最多的边,那么最后的图中,肯定两个集合,这两个集合都是强联通的,

一个集合到一个集合只有单向边。我们先让图是满图,然后通过删边来求的:有n*(n-1)条边,然后删掉已有的边m

,然后还有删掉两个集合的边n1*(n-n1),n1为其中一个集合的顶点个数,因为这里是单向边。

那么答案就是ans=n*(n-1)-m-n1*(n-n1),

我们要使ans最大,那么n1*(n-n1)就要越小

 最终添加完边的图,肯定可以分成两个部 X 和 Y ,其中只有X到Y的边没有Y到X的边,那么要使得边数尽可能的多,则X部肯定是一个完全图,Y部也是,同时X部中每个点到Y部的每个点都有一条边,假设X部有x个点,Y部有y个点,有x+y=n,同时边数F=x*y+x*(x-1)+y*(y-1),整理得:F=N*N-N-x*y,(然后去掉已经有了的边m,就是答案),当x+y为定值时,二者越接近,x*y越大,所以要使得边数最多,那么X部和Y部的点数的个数差距就要越大,所以首先对于给定的有向图缩点,对于缩点后的每个点,如果它的出度或者入度为0,那么它才有可能成为X部或者Y部,所以只要求缩点之后的出度或者入度为0的点中,包含节点数最少的那个点,令它为一个部,其它所有点加起来做另一个部,就可以得到最多边数的图了

  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<vector>
  4. #include<algorithm>
  5. #define N 100005
  6. #define INF 0xfffffff
  7. using namespace std;
  8.  
  9. int head[N], cnt;
  10. int top, Is[N], Stack[N], low[N], dfn[N], Time, n, m;
  11. int nBlock, Block[N];
  12. int Cnt[N], Out[N], In[N];
  13. struct Edge
  14. {
  15. int v, next;
  16. }e[N];
  17. void Init()
  18. {
  19. Time = cnt = top = nBlock = ;
  20. memset(Cnt, , sizeof(Cnt));
  21. memset(low, , sizeof(low));
  22. memset(dfn, , sizeof(dfn));
  23. memset(Stack, , sizeof(Stack));
  24. memset(Is, , sizeof(Is));
  25. memset(Out, , sizeof(Out));
  26. memset(In, , sizeof(In));
  27. memset(Block, , sizeof(Block));
  28. memset(head, -, sizeof(head));
  29. }
  30. void Add(int u, int v)
  31. {
  32. e[cnt].v = v;
  33. e[cnt].next = head[u];
  34. head[u] = cnt++;
  35. }
  36. void Tajar(int u, int father)
  37. {
  38. Stack[top++]=u;
  39. low[u] = dfn[u] = ++Time;
  40. Is[u] = ;
  41. int v;
  42. for(int i=head[u]; i!=-; i=e[i].next)
  43. {
  44. v = e[i].v;
  45. if(!dfn[v])
  46. {
  47. Tajar(v, u);
  48. low[u] = min(low[u], low[v]);
  49. }
  50. else if(Is[v])
  51. low[u] = min(low[u], dfn[v]);
  52. }
  53. if(low[u]==dfn[u])
  54. {
  55. ++nBlock;
  56. do
  57. {
  58. v=Stack[--top];
  59. Is[v] = ;
  60. Block[v] = nBlock;
  61. Cnt[nBlock]++;
  62. }while(u!=v);
  63. }
  64. }
  65.  
  66. int main()
  67. {
  68. int T, t=, x, y;
  69. scanf("%d", &T);
  70. while(T--)
  71. {
  72. Init();
  73. scanf("%d%d", &n, &m);
  74. for(int i=; i<=m; i++)
  75. {
  76. scanf("%d%d", &x, &y);
  77. Add(x, y);
  78. }
  79. for(int i=; i<=n; i++)
  80. {
  81. if(!low[i])
  82. Tajar(i, -);
  83. }
  84. for(int i=; i<=n; i++)
  85. {
  86. for(int j=head[i]; j!=-; j=e[j].next)
  87. {
  88. int u = Block[i];
  89. int v = Block[e[j].v];
  90. if(u != v)
  91. {
  92. Out[v]++;
  93. In[u]++;
  94. }
  95. }
  96. }
  97. y = INF;
  98. for(int i=; i<=nBlock; i++)
  99. {
  100. if(!In[i] || !Out[i])
  101. y=min(y, Cnt[i]);
  102. }
  103. x = n - y;
  104. long long ans=(long long)n*(n-)-x*y-m;
  105. if(nBlock==)
  106. printf("Case %d: -1\n", t++);
  107. else
  108. printf("Case %d: %lld\n", t++, ans);
  109. }
  110. return ;
  111. }

一年之后又来写

  1. #include<iostream>
  2. #include<stdio.h>
  3. #include<algorithm>
  4. #include<math.h>
  5. #include<string.h>
  6. #include<string>
  7. #include<stack>
  8. #include<vector>
  9. #include<map>
  10. using namespace std;
  11. #define N 100305
  12. #define INF 0x3f3f3f3f
  13. #define met(a, b) memset(a, b, sizeof(a))
  14. typedef long long LL;
  15.  
  16. vector<vector<int> >G;
  17. stack<int>sta;
  18. int low[N], dfn[N], block[N], Block, vis[N];
  19. int In_degree[N], Out_degree[N], Time, n, cnt[N];
  20.  
  21. void Init()
  22. {
  23. met(low, );
  24. met(dfn, );
  25. met(block, );
  26. met(vis, );
  27. met(In_degree, );
  28. met(Out_degree, );
  29. met(cnt, );
  30. G.clear();
  31. G.resize(n+);
  32. while(sta.size())sta.pop();
  33. Time = Block = ;
  34. }
  35.  
  36. void Tarjan(int u)
  37. {
  38. low[u] = dfn[u] = ++Time;
  39. sta.push(u);
  40. vis[u] = ;
  41. int len = G[u].size(), v;
  42. for(int i=; i<len;i++)
  43. {
  44. v = G[u][i];
  45. if(!dfn[v])
  46. {
  47. Tarjan(v);
  48. low[u] = min(low[u], low[v]);
  49. }
  50. else if(vis[v])
  51. {
  52. low[u] = min(low[u], dfn[v]);
  53. }
  54. }
  55. if(low[u] == dfn[u])
  56. {
  57. Block++;
  58. do{
  59. v = sta.top();
  60. sta.pop();
  61. block[v] = Block;
  62. cnt[Block]++;
  63. vis[v] = ;
  64. }while(u!=v);
  65. }
  66. }
  67.  
  68. int main()
  69. {
  70. int T, m, t = , u, v;
  71. scanf("%d", &T);
  72. while(T--)
  73. {
  74. scanf("%d %d", &n, &m);
  75. Init();
  76. for(int i=; i<=m; i++)
  77. {
  78. scanf("%d %d", &u, &v);
  79. G[u].push_back(v);
  80. }
  81. for(int i=; i<=n; i++)
  82. {
  83. if(!dfn[i])
  84. Tarjan(i);
  85. }
  86. if(Block == )
  87. {
  88. printf("Case %d: -1\n", t++);
  89. continue;
  90. }
  91. for(int i=; i<=n; i++)
  92. {
  93. int len = G[i].size();
  94. for(int j=; j<len; j++)
  95. {
  96. u = block[i];
  97. v = block[G[i][j]];
  98. if(u != v)
  99. {
  100. In_degree[v]++;
  101. Out_degree[u]++;
  102. }
  103. }
  104. }
  105. int ans = , sum = n*(n-) - m;
  106.  
  107. for(int i=; i<=Block; i++)
  108. {
  109. if(!In_degree[i] || !Out_degree[i])
  110. ans = max(ans, sum - cnt[i]*(n-cnt[i]));
  111. }
  112. printf("Case %d: %d\n", t++, ans);
  113. }
  114. return ;
  115. }

Strongly connected---hdu4635(强联通分量)的更多相关文章

  1. Strongly connected(hdu4635(强连通分量))

    /* http://acm.hdu.edu.cn/showproblem.php?pid=4635 Strongly connected Time Limit: 2000/1000 MS (Java/ ...

  2. 强联通分量(tarjan算法+算法简介)

    题目描述 ›对于一个有向图顶点的子集S,如果在S内任取两个顶点u和v,都能找到一条从u到v的路径,那么就称S是强连通的.如果在强连通的顶点集合S中加入其他任意顶点集合后,它都不再是强连通的,那么就称S ...

  3. Kosaraju算法---强联通分量

    1.基础知识 所需结构:原图.反向图(若在原图中存在vi到vj有向边,在反向图中就变为vj到vi的有向边).标记数组(标记是否遍历过).一个栈(或记录顶点离开时间的数组).      算法描叙: :对 ...

  4. [CF #236 (Div. 2) E] Strictly Positive Matrix(强联通分量)

    题目:http://codeforces.com/contest/402/problem/E 题意:给你一个矩阵a,判断是否存在k,使得a^k这个矩阵全部元素都大于0 分析:把矩阵当作01矩阵,超过1 ...

  5. UVa 11324 & 强联通分量+DP

    题意: 一张无向图,求点集使其中任意两点可到达. SOL: 强联通分量中的点要么不选要么全都选,然后缩点DAG+DP 记录一下思路,不想写了...代码满天飞.

  6. BZOJ 1051 & 强联通分量

    题意: 怎么说呢...这种题目有点概括不来....还是到原题面上看好了... SOL: 求出强联通分量然后根据分量重构图,如果只有一个点没有出边那么就输出这个点中点的数目. 对就是这样. 哦还有论边双 ...

  7. 洛谷 P2661 信息传递 Label:并查集||强联通分量

    题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...

  8. POJ 2186-Popular Cows (图论-强联通分量Korasaju算法)

    题目链接:http://poj.org/problem?id=2186 题目大意:有n头牛和m对关系, 每一对关系有两个数(a, b)代表a牛认为b牛是“受欢迎”的,且这种关系具有传递性, 如果a牛认 ...

  9. POJ 1904 King's Quest 强联通分量+输入输出外挂

    题意:国王有n个儿子,现在这n个儿子要在n个女孩里选择自己喜欢的,有的儿子可能喜欢多个,最后国王的向导给出他一个匹配.匹配有n个数,代表某个儿子和哪个女孩可以结婚.已知这些条件,要你找出每个儿子可以和 ...

随机推荐

  1. Kubernetes(一)初探

    Kubernetes是Google开源的容器集群管理系统.它构建于docker技术之上,为容器化的应用提供资源调度.部署运行.服务发现.扩容缩容等整一套功能,本质上可看作是基于容器技术的mini-Pa ...

  2. hadoop学习笔记之-hbase完全分布模式安装-5

    http://blog.csdn.net/lichangzai/article/details/8441975 http://blog.csdn.net/jpiverson/article/detai ...

  3. 搭建 FTP 文件服务vsftpd

    安装并启动 FTP 服务 安装 VSFTPD 使用 yum 安装 vsftpd: yum install vsftpd -y vsftpd 是在 Linux 上被广泛使用的 FTP 服务器,根据其[官 ...

  4. mybatis由浅入深day02_课程复习_1订单商品数据模型分析

    mybatis第二天  高级映射 查询缓存 和spring整合 课程复习: mybatis是什么? mybatis是一个持久层框架,mybatis是一个不完全的ORM框架.sql语句需要程序员自己去编 ...

  5. Javascript 字符串替换

    <!DOCTYPE html><html><head> <meta http-equiv="Content-Type" content=& ...

  6. shell基础篇(五)条件判断

    写脚本时:有时要判断字符串是否相等,数字测试.这对后面学习的shell语句,循环,条件语句做好基础. 条件判断格式  1. test condition : test命令  2. [ conditio ...

  7. Python 内部类

    内部类也就是在类的内部再定义类,如下: #!/usr/bin/env python #-*- coding:utf-8 -*- class People(object): class Chinese( ...

  8. 在联网时,两台linux服务器传输文件方法

    登陆服务器root用户命令:su - root 传输文件命令:scp +需要传输linux系统文件+空格+目标linux服务器的用户名@服务器ip地址:+传输的文件路径:例:scp /mnt/work ...

  9. thinkjs——redis

    前言: 后台某些操作的时候会用到缓存:比如用户登录或者校验次数的情景.而本次遇见的状况就是在点击“推送”按钮的时候,需要判断缓存中是否有其值,并将其次数限制为固定值. 过程: 刚听到此需求的时候,首先 ...

  10. glassfish任意文件读取漏洞解析

    一.背景: glassfish是一款java编写的跨平台的开源的应用服务器. 二.漏洞原理: 与宽字节SQL注入一致,都是由于unicode编码歧义导致的.具体payload如下构造: http:// ...