题目链接: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 最小了。

代码如下:

#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
#define maxn 100008
using namespace std;
typedef long long ll;
int cnt, Index, tot, sum;
int head[maxn], low[maxn], dfn[maxn], q[maxn];
int in[maxn],out[maxn];
int qhead[maxn];
bool vis[maxn];
int pre[maxn];
ll ans[maxn],n,m;
struct Edge
{
int to;
int next;
}edge[maxn << ];
inline void add(int u, int v)
{
edge[++cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt;
return;
}
inline void tarjan(int u)
{
low[u] = dfn[u] = ++Index;
q[++tot] = u;
vis[u] = true;
for (int i = head[u]; i; i = edge[i].next)
{
int v = edge[i].to;
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (vis[v]) low[u] = min(low[u], dfn[v]);
}
if (low[u] == dfn[u])
{
++sum;
do {
ans[sum]++;
pre[q[tot]] = sum;
vis[q[tot--]] = false;
} while (q[tot + ] != u);
}
return;
}
void init()
{
cnt=Index=tot=sum=;
for(int i=;i<=n;i++) dfn[i]=vis[i]=head[i]=qhead[i]=ans[i]=in[i]=out[i]=;
memset(edge,,sizeof(edge));
return;
}
int main()
{
int t;
scanf("%d",&t);
int T=;
while(t--){
init();
scanf("%lld%lld", &n, &m);
int A, B;
for (int i = ; i <= m; i++) {
scanf("%d%d", &A, &B);
add(A, B);
}
for (int i = ; i <= n; i++) {
if (!dfn[i]) tarjan(i);
}
if(sum==){ printf("Case %d: -1\n",++T ); continue;}
cnt = ;
for (int i = ; i <= n; i++) {
for (int j = head[i]; j; j = edge[j].next) {
int v = edge[j].to;
if (pre[i] != pre[v]){
in[pre[v]]++,out[pre[i]]++;
}
}
}
ll res=0x3f3f3f3f;
for(int i=;i<=sum;i++){
if(in[i]==||out[i]==){
res=min(res,ans[i]);
}
}
res=1ll*n*n-n-m-res*(n-res);
printf("Case %d: %lld\n",++T,res );
}
}

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. Bzoj 4582 [Usaco2016 Open] Diamond Collector 题解

    4582: [Usaco2016 Open]Diamond Collector Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 204  Solved: ...

  2. 对于springboot的几种注入方法的个人看法

    最近在知乎上面看到一篇关于程序员面试的问题,面试官问我们一般有几种注入的方法,这几种注入的方法分别在什么时候运用比合理,当时我看到这个时候懵逼了,由于我自己也是刚刚接触springboot不久,所以就 ...

  3. 第一章 Servlet

    JavaEEe技术包括Servlet/Jsp.Java Message Service(JMS).Enterprise JavaBeans(EJB).JavaServer Faces(JSF),以及J ...

  4. 一文带你了解git

    git简介 什么是git? git是当今世界上最先进的分布式的版本控制系统. 版本控制系统分集中式的和分布式的,集中式的主要代表有CVS.SVN,而Git是分布式版本控制系统的佼佼者. 那什么是集中式 ...

  5. Atlassian In Action-Jira之核心插件(三)

    目录 BigPicture BigPicture特点介绍 管理员管理菜单 任务列表 任务管理 设置 最佳实践 Jira Misc Workflow Extensions 最佳实践 自动分配 自动化流程 ...

  6. Excel催化剂开源第19波-一些虽简单但不知道时还是很难受的知识点

    通常许多的知识都是在知与不知之间,不一定非要很深奥,特别是Excel这样的应用工具层面,明明已经摆在那里,你不知道时,永远地不知道,知道了,简单学习下就已经实现出最终的功能效果. 在程序猿世界里,也是 ...

  7. [剑指offer] 3. 从头到尾打印链表

    题目描述 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList. 思路: 利用容器,遍历一遍加入到一个新容器里,然后反置输出. vector 用 reverse stack 则直接一个个出栈 ...

  8. 用python输出回文数

    一个b站上的朋友问我,怎么返回五位数的回文数的个数. 我首先百度回文数的概念,就是正读和倒读都一样的数字,例如:10001,99899 等等 数字的位数拆分一头雾水,思来想去,用字符串的方法完美解决! ...

  9. Http接口调用示例教程

    介绍HttpClient库的使用前,先介绍jdk里HttpURLConnection,因为HttpClient是开源的第三方库,使用方便,不过jdk里的都是比较基本的,有时候没有HttpClient的 ...

  10. 跟着大彬读源码 - Redis 7 - 对象编码之简单动态字符串

    Redis 没有直接使用 C 语言传统的字符串表示(以空字符串结尾的字符数组),而是构建了一种名为简单动态字符串(simple dynamic string)的抽象类型,并将 SDS 用作 Redis ...