[HDU4635] Strongly connected
传送门:>Here<
题意:给出一张DAG,问最多添加几条边(有向)使其强连通分量个数大于1
解题思路
最少添加几条边使其强连通我们是知道的,非常简单,就是入度为0的点与出度为0的点的较大值
但是最多添加几条边使其依然不强连通,这个问题比较复杂——但这题的解法实在是太妙了
可以倒过来想:最多可以添加几条边?很显然,对于一张$n$个点的有向图,至多$n(n-1) / 2$条边,因此总共可以再添加$[n(n-1) / 2] - M$条边。但是添加满所有的边以后肯定会使整个图成为一个强连通分量,因此我们需要把多余的边减掉。怎么减掉呢?可以贪心地思考:由于要让强连通分量大于1且边数最多,最优的情况一定是两个强连通分量,这样加的边最多。
因此我们可以设最后留下两个强连通分量,其中第一个强连通分量内点的个数为$x$,第二个为$y$。很显然$x+y = n$因此最后的边的数量最多是$x*(x-1) + y*(y-1) + x*y$。最后之所以加上$x*y$,是因为我们可以把其中一个强连通分量统统向第二个强连通分量的每一个点连相同方向的边,总共可以连$x*y$条
我们可以化简刚才的式子:
$$x*(x-1) + y*(y-1) + x*y$$$$= x*x - x + y*y - y + x*y$$$$= (x+y)^2 - n - x*y$$$$= n^2 - n - x*y$$
由于$n^2 - n$肯定是确定的,为使边数最多,要让$x*y$尽量小
已知$x+y$的值是确定的,因此$x$和$y$的差一定是越大越好。也就是其中一个要尽量小。由于$x$和$y$分别都是强连通分量,我们可以先对原图进行缩点,然后找出最小的$x$进行计算
然而并不是每一个强连通分量都可以作为$x$的,由于根据我们前面的假设,只能有两个强连通分量,因此作为x的强连通分量在缩点完成后的DAG中不能既有入度又有出度,这样的话前后都包含了强连通分量,就一定不止两个了——换句话说,如果这样的$x$作为一个来计算的话,他往别人或别人往他那里连边的时候一定会形成环。
Code
注意有多组数据,一定要初始化
/*by DennyQi*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define r read()
#define Max(a,b) (((a)>(b))?(a):(b))
#define Min(a,b) (((a)<(b))?(a):(b))
using namespace std;
typedef long long ll;
const int MAXN = ;
const int INF = 0x3f3f3f3f;
const int MOD = ;
inline int read(){
int x = ; int w = ; register unsigned char c = getchar();
for(; c^'-' && (c < '' || c > ''); c = getchar());
if(c == '-') w = -, c = getchar();
for(; c >= '' && c <= ''; c = getchar()) x = (x<<) + (x<<) + c - '';
return x * w;
}
int T,N,M,x[MAXN],y[MAXN],Case;
int first[MAXN],nxt[MAXN],to[MAXN],num_edge;
int dfn[MAXN],low[MAXN],scc[MAXN],sta[MAXN],sccno[MAXN],amt[MAXN],rd[MAXN],cd[MAXN],top,scc_cnt,dfs_clock;
inline void Init(){
memset(first,,sizeof(first));
memset(nxt,,sizeof(nxt));
memset(to,,sizeof(to));
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
memset(sta,,sizeof(sta));
memset(sccno,,sizeof(sccno));
memset(amt,,sizeof(amt));
memset(rd,,sizeof(rd));
memset(cd,,sizeof(cd));
num_edge = ;
dfs_clock = ;
scc_cnt = ;
top = ;
}
inline void add(int u, int v){
to[++num_edge] = v;
nxt[num_edge] = first[u];
first[u] = num_edge;
}
void tarjan(int u){
dfn[u] = low[u] = ++dfs_clock;
sta[++top] = u;
int v;
for(int i = first[u]; i; i = nxt[i]){
v = to[i];
if(!dfn[v]){
tarjan(v);
low[u] = Min(low[u], low[v]);
}
else if(!sccno[v]){
low[u] = Min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u]){
++scc_cnt;
while(){
sccno[sta[top]] = scc_cnt;
++amt[scc_cnt];
if(sta[top--] == u) break;
}
}
}
int main(){
// freopen(".in","r",stdin);
T=r;
while(T--){
++Case;
printf("Case %d: ", Case);
Init();
N=r,M=r;
for(int i = ; i <= M; ++i){
x[i]=r,y[i]=r;
add(x[i], y[i]);
}
for(int i = ; i <= N; ++i){
if(!dfn[i]){
tarjan(i);
}
}
/* for(int i = 1; i <= N; ++i){
printf("sccno[%d] = %d\n", i, sccno[i]);
}*/
if(scc_cnt == ){
printf("-1\n");
continue;
}
for(int i = ; i <= M; ++i){
if(sccno[x[i]] != sccno[y[i]]){
++rd[sccno[y[i]]];
++cd[sccno[x[i]]];
}
}
int _min = INF;
for(int i = ; i <= scc_cnt; ++i){
if(rd[i]!= && cd[i]!=) continue;
_min = Min(_min, amt[i]);
}
// printf("_min = %d\n", _min);
printf("%d\n", N*(N-) - _min*(N-_min) - M);
}
return ;
}
[HDU4635] Strongly connected的更多相关文章
- HDU-4635 Strongly connected 强连通,缩点
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4635 题意:给一个简单有向图(无重边,无自环),要你加最多的边,使得图还是简单有向图... 先判断图是 ...
- HDU4635 Strongly connected【强连通】
题意: 给一个n个点的简单有向图,问最多能加多少条边使得该图仍然是简单有向图,且不是强连通图.简单有向图的定义为:没有重边,无自环. 强连通图的定义为:整个图缩点后就只有一个点,里面包含n个原点,也就 ...
- Strongly connected(hdu4635(强连通分量))
/* http://acm.hdu.edu.cn/showproblem.php?pid=4635 Strongly connected Time Limit: 2000/1000 MS (Java/ ...
- PTA Strongly Connected Components
Write a program to find the strongly connected components in a digraph. Format of functions: void St ...
- algorithm@ Strongly Connected Component
Strongly Connected Components A directed graph is strongly connected if there is a path between all ...
- cf475B Strongly Connected City
B. Strongly Connected City time limit per test 2 seconds memory limit per test 256 megabytes input s ...
- 【CF913F】Strongly Connected Tournament 概率神题
[CF913F]Strongly Connected Tournament 题意:有n个人进行如下锦标赛: 1.所有人都和所有其他的人进行一场比赛,其中标号为i的人打赢标号为j的人(i<j)的概 ...
- HDU 4635 Strongly connected (Tarjan+一点数学分析)
Strongly connected Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) ...
- 【CodeForces】913 F. Strongly Connected Tournament 概率和期望DP
[题目]F. Strongly Connected Tournament [题意]给定n个点(游戏者),每轮游戏进行下列操作: 1.每对游戏者i和j(i<j)进行一场游戏,有p的概率i赢j(反之 ...
随机推荐
- python 打包下载 zipfile & tarfile
看百度网盘我们会发现这么一个需求,新建一个文件夹,然后向文件夹中上传文件,点击文件夹可以直接下载,下载的是一个压缩文件,将文件夹中所有文件全部打包了下载下来. 在python中,我们要做文件打包下载, ...
- python爬虫随笔(2)—启动爬虫与xpath
启动爬虫 在上一节中,我们已经创建好了我们的scrapy项目,看着这一大堆文件,想必很多人都会一脸懵逼,我们应该怎么启动这个爬虫呢? 既然我们采用cmd命令创建了scrapy爬虫,那就得有始有终有逼格 ...
- GitHub上README.md编写教程(基本语法)
一.标题写法: 第一种方法: 1.在文本下面加上 等于号 = ,那么上方的文本就变成了大标题.等于号的个数无限制,但一定要大于0个哦.. 2.在文本下面加上 下划线 - ,那么上方的文本就变成了中标题 ...
- dfs实现数的全排列
代码 #include<bits/stdc++.h> using namespace std; #define ll long long bool vis[15]; int a[15]; ...
- (Beta)Let's-M2后分析报告
设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 在M1阶段我们对用户需求进行了调研,同时M1阶段我们的开发目标就是为了解决用户发起.参与.查看.搜 ...
- ad2017安装以及破解
1.破Ad破解https://wenku.baidu.com/view/5e23a78e2e3f5727a5e962dd.html 2. Ad 汉化https://jingyan.baidu.com/ ...
- 软工网络15团队作业7——Alpha冲刺之事后诸葛亮
Deadline: 2018-5-16 22:00PM,以博客提交至班级博客时间为准 事后诸葛亮分析 Alpha冲刺,很多同学经历了"Learning by doing"的学一门新 ...
- scp Permission denied
https://blog.csdn.net/xlgen157387/article/details/49818259
- C# foreach内部原理
我们知道使用foreach的一个要求是对象必须继承自IEnumerable接口 这样才可以进行迭代 那内部是怎么实现的呢 这个时候会将对应的foreach语句转换为一个while循环 并且通过Move ...
- [转帖]windows7/windows NT介绍
windows7/windows NT介绍 原文应该是IT168发布的 但是一直没找到 感觉看了之后 明白了很多 技术都是互相融合的 没有严格意义上的对立直说. Windows 7/Windows ...