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) ...
随机推荐
- os.path.dirname(__file__)
os.path.dirname(__file__) 返回脚本的路径 描述: 必须实际存在的.py文件,如果直接在命令行执行,则会引发异常NameError: name 'file' is not de ...
- C++智能指针的几种用法
auto在c++11中已经弃用. 一.auto_ptr模板 auto_ptr与shared_ptr.unique_ptr都定义了类似指针的对象,可以将new到的地址赋给这一对象,当智能指针过期时,析构 ...
- 设计模式:代理模式是什么,Spring AOP还和它有关系?
接着学习设计模式系列,今天讲解的是代理模式. 定义 什么是代理模式? 代理模式,也叫委托模式,其定义是给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用.它包含了三个角色: Subject: ...
- 热度3年猛增20倍,Serverless&云开发的技术架构全解析
『 作为一个不断发展的新兴技术, Serverless 热度的制高点已然到来.』 或许,Google Trends 所显示的 3 年猛增 20 倍的" Serverless " 搜 ...
- String到底在内存中是如何存储的
String会出现在哪些地方 方法内的局部string 类内的字段String static string 容器中存储的string String数组 那么String的位置会影响其存储方式吗? 显然 ...
- 学习使用Quartz,java
报名立减200元.暑假直降6888. 邀请链接:http://www.jnshu.com/login/1/20535344 邀请码:20535344 Quartz官网 添加quartz到Java应用中 ...
- secureCRT背景颜色
secureCRT是我们常用的linux远程登录软件,某些情况下我们安装的secureCRT工具可能默认背景颜色为白色,使用时很容易造成眼睛的疲劳,网上有些教程也只是修改当前登录窗口背景颜色,新的连接 ...
- .net持续集成cake篇之cake任务依赖、自定义配置荐及环境变量读取
系列目录 新建一个构建任务及任务依赖关系设置 上节我们通过新建一个HelloWorld示例讲解了如何编写build.cake以及如何下载build.ps1启动文件以及如何运行.实际项目中,我们使用最多 ...
- Spring Aware 到底是什么?
通过如下前序两篇文章: Spring Bean 生命周期之"我从哪里来"? Spring Bean 生命周期之"我要到哪里去"? 我们了解了 Spring Be ...
- 项目中操作redis改brpop阻塞模式为订阅模式的实现-java实习笔记二
更改项目需求以及项目之前阻塞模式问题的叙述已经在上一篇说过了,详情可参考:https://www.cnblogs.com/darope/p/10276213.html ,https://yq.ali ...