传送门:>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的更多相关文章

  1. HDU-4635 Strongly connected 强连通,缩点

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4635 题意:给一个简单有向图(无重边,无自环),要你加最多的边,使得图还是简单有向图... 先判断图是 ...

  2. HDU4635 Strongly connected【强连通】

    题意: 给一个n个点的简单有向图,问最多能加多少条边使得该图仍然是简单有向图,且不是强连通图.简单有向图的定义为:没有重边,无自环. 强连通图的定义为:整个图缩点后就只有一个点,里面包含n个原点,也就 ...

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

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

  4. PTA Strongly Connected Components

    Write a program to find the strongly connected components in a digraph. Format of functions: void St ...

  5. algorithm@ Strongly Connected Component

    Strongly Connected Components A directed graph is strongly connected if there is a path between all ...

  6. cf475B Strongly Connected City

    B. Strongly Connected City time limit per test 2 seconds memory limit per test 256 megabytes input s ...

  7. 【CF913F】Strongly Connected Tournament 概率神题

    [CF913F]Strongly Connected Tournament 题意:有n个人进行如下锦标赛: 1.所有人都和所有其他的人进行一场比赛,其中标号为i的人打赢标号为j的人(i<j)的概 ...

  8. HDU 4635 Strongly connected (Tarjan+一点数学分析)

    Strongly connected Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) ...

  9. 【CodeForces】913 F. Strongly Connected Tournament 概率和期望DP

    [题目]F. Strongly Connected Tournament [题意]给定n个点(游戏者),每轮游戏进行下列操作: 1.每对游戏者i和j(i<j)进行一场游戏,有p的概率i赢j(反之 ...

随机推荐

  1. 旋转数组的最小数字 - 剑指offer 面试题8

    题目描述: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋 ...

  2. Python-collections模块-57

    返回顶部 模块的导入和使用 模块的导入应该在程序开始的地方 更多相关内容 http://www.cnblogs.com/Eva-J/articles/7292109.html   常用模块 colle ...

  3. Wannafly挑战赛28

    总结- A-开始觉得是找规律,最开始模拟当时我觉得如果L达到1e9的范围的话,岂不是要加1e9次,模拟也就没有认真写,现在想来,后面由于加的不再是1,而是我前面的值,这样相当了一个斐波那契的类型,而斐 ...

  4. Final Destination II -- 矩阵快速幂模板题

    求f[n]=f[n-1]+f[n-2]+f[n-3] 我们知道 f[n] f[n-1] f[n-2]         f[n-1]  f[n-2]  f[n-3]         1    1    ...

  5. poj2104 主席树裸题

    空间大小:n*lgn 复杂度:建树n*lgn  查询lgn #include <cstdio> #include <iostream> #include <algorit ...

  6. D1. Great Vova Wall (Version 1)

    链接 [https://codeforces.com/contest/1092/problem/D1] 题意 给你n个位置墙的高度,现在你有2×1 砖块,你可以竖直或者水平放置 问你是否可以使得所有位 ...

  7. docker之导出、导入、数据搬迁

    docker 导出 导入有二种,一种是备份镜像,一种备份容器.数据搬迁,最简单粗暴就是直接COPY,volume的路径就行了. 一.导出导入镜像 #导出为tar docker save #ID or  ...

  8. Lombok 安装、入门以及使用

    lombok 的官方网址:http://projectlombok.org/ lombok 安装    使用 lombok 是需要安装的,如果不安装,IDE 则无法解析 lombok 注解.先在官网下 ...

  9. 【学习总结】GirlsInAI ML-diary day-5-布尔表达式/Bool

    [学习总结]GirlsInAI ML-diary 总 原博github链接-day5 认识布尔表达式 简单来说,bool 就是对错判断. 给个条件,如果满足条件就返回True, 不满足条件就返回Fal ...

  10. vue图表

    https://www.cnblogs.com/powertoolsteam/p/top-9-javascript-charting-libraries.html