HDU 4635 (完全图 和 有向图缩点)
题目链接: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 (完全图 和 有向图缩点)的更多相关文章
- hdu 4635 Strongly connected 强连通缩点
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4635 题意:给你一个n个点m条边的图,问在图不是强连通图的情况下,最多可以向图中添多少条边,若图为原来 ...
- Strongly connected HDU - 4635(判断强连通图 缩点)
找出强联通块,计算每个连通块内的点数.将点数最少的那个连通块单独拿出来,其余的连通块合并成一个连通分量. 那么假设第一个连通块的 点数是 x 第二个连通块的点数是 y 一个强连通图(每两个点之间,至 ...
- hdu 3072 有向图缩点成最小树形图计算最小权
题意,从0点出发,遍历所有点,遍历边时候要付出代价,在一个SCC中的边不要付费.求最小费用. 有向图缩点(无需建立新图,,n<=50000,建则超时),遍历边,若不在一个SCC中,用一个数组更新 ...
- hdu 1827 有向图缩点看度数
题意:给一个有向图,选最少的点(同时最小价值),从这些点出发可以遍历所有. 思路:先有向图缩点,成有向树,找入度为0的点即可. 下面给出有向图缩点方法: 用一个数组SCC记录即可,重新编号,1.... ...
- HDU 4635 —— Strongly connected——————【 强连通、最多加多少边仍不强连通】
Strongly connected Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u ...
- HDU 4635 Strongly connected (强连通分量)
题意 给定一个N个点M条边的简单图,求最多能加几条边,使得这个图仍然不是一个强连通图. 思路 2013多校第四场1004题.和官方题解思路一样,就直接贴了~ 最终添加完边的图,肯定可以分成两个部X和Y ...
- HDU 4635 - Strongly connected(2013MUTC4-1004)(强连通分量)
t这道题在我们队属于我的范畴,最终因为最后一个环节想错了,也没搞出来 题解是这么说的: 最终添加完边的图,肯定可以分成两个部X和Y,其中只有X到Y的边没有Y到X的边,那么要使得边数尽可能的多,则X部肯 ...
- hdu 4635 Strongly connected(Tarjan)
做完后,看了解题报告,思路是一样的.我就直接粘过来吧 最终添加完边的图,肯定可以分成两个部X和Y,其中只有X到Y的边没有Y到X的边,那么要使得边数尽可能的多,则X部肯定是一个完全图,Y部也是,同时X部 ...
- HDU 4635 Strongly connected (Tarjan+一点数学分析)
Strongly connected Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) ...
随机推荐
- Innovus教程 - Flow系列 - MMMC分析环境的配置概述(理论+实践+命令)
本文转自:自己的微信公众号<集成电路设计及EDA教程> <Innovus教程 - Flow系列 - MMMC分析环境的配置概述(理论+实践+命令)> 轻轻走过,悄悄看过,无 ...
- bzoj 2752 9.20考试第三题 高速公路(road)题解
2752: [HAOI2012]高速公路(road) Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1545 Solved: 593[Submit] ...
- 树链剖分 [JLOI2014]松鼠的新家
[JLOI2014]松鼠的新家 时间限制: 1 Sec 内存限制: 128 MB 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达, ...
- [WPF自定义控件库]了解WPF的布局过程,并利用Measure为Expander添加动画
1. 前言 这篇文章介绍WPF UI元素的两步布局过程,并且通过Resizer控件介绍只使用Measure可以实现些什么内容. 我不建议初学者做太多动画的工作,但合适的动画可以引导用户视线,提升用户体 ...
- [PTA] 数据结构与算法题目集 6-4 链式表的按序号查找 & 6-5 链式表操作集 & 6-6 带头结点的链式表操作集
带不带头结点的差别就是,在插入和删除操作中,不带头结点的链表需要考虑两种情况:1.插入(删除)在头结点.2.在其他位置. 6.4 //L是给定单链表,函数FindKth要返回链式表的第K个元素.如果该 ...
- 并发,并行,线程,进程,GIL锁
1.并发和并行 并发: 同时做某些事,但是强调同一时段做多件事 如:同一路口,发生了车辆要同时通过路面的时间. 并行: 互不干扰的在同一时刻做多件事 如:同一时刻,同时有多辆车在多条车道上跑,即同时发 ...
- 如何使用 nvm-windows 管理 nodejs 版本
写在前边的话: (1). 路径一定不要包含空格,如 Program Files 这样,所以有把程序安装到 D:\Program Files 文件下的同学请注意了:(2). 为了避免 nvm 无法切换源 ...
- 深入理解Java中的锁(三)
ReadWriteLock接口 读写锁维护一对关联锁,一个只用于读操作,一个只用于写操作.读锁可以由多个线程同时持有,又称共享锁.写锁同一时间只能由一个线程持有,又称互斥锁.同一时间,两把锁不能被不同 ...
- web前端开发-博客目录
web前端开发是一个新的领域,知识连接范围广,处于设计与后端数据交互的桥梁,并且现在很多web前端相关语言标准,框架库都在高速发展.在学习过程中也常常处于烦躁与迷茫,有时候一直在想如何能够使自己更加系 ...
- 01 | 健康之路 kubernetes(k8s) 实践之路 : 开篇及概况
近几年容器相关的技术大行其道,容器.docker.k8s.mesos.service mesh.serverless等名词相信大家多少都有听过,国内互联网公司无一不接触和使用相关技术. 健康之路早在2 ...