传送门:>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. Leetcode -- 394. Decode String

    Given an encoded string, return it's decoded string. The encoding rule is: k[encoded_string], where ...

  2. 用Flask+Redis维护代理池

    GitHub:https://github.com/LXL-YAN/ProxyPool 视频讲解:https://www.bilibili.com/video/av19057145/?p=17

  3. 使用 Markdown编辑

    作用: 学习笔记,整理日志, 发布日记,杂文,所见所想 撰写发布技术文稿(代码支持) 撰写发布学术论文(LaTeX 公式支持) sublime text3插件 输入 Shift + Ctrl + P, ...

  4. Spring Data Elasticsearch 和 x-pack 用户名/密码验证连接

    Elasticsearch Java API 客户端连接 一个是TransportClient,一个是NodeClient,还有一个XPackTransportClient TransportClie ...

  5. Iar8.1安装包破解

    Iar8.1安装包链接链接:https://pan.baidu.com/s/1F6sxEcatk3_YPq47lvc8Mw 密码:mnlz 破解链接  https://www.cnblogs.com/ ...

  6. javaweb之Cookie学习

    Cookie简介 HTTP是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分中两次请求是否由一个客户端发出.这样的设计严重阻碍的Web程序的设计.如:在我们进行网购时,买了一条裤子, ...

  7. Django组件之认证系统

      Django自带的用户认证 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能,这还真是个麻烦的事情呢. Dja ...

  8. 多线程系列之三:Immutable 模式

    一,什么是Immutable模式?immutable就是不变的,不发生改变的.Immutable模式中存在着确保实例状态不发生变化改变的类.这些实例不需要互斥处理.String就是一个Immutabl ...

  9. MySQL数据性能优化-修改方法与步骤

    原文:http://bbs.landingbj.com/t-0-240421-1.html 数据库优化应该是每个设计到数据库操作应用必须涉及到的操作. 经常调试修改数据库性能主要有三个方面 1.MyS ...

  10. opencv2\core\cuda.hpp(106): error C2059: 语法错误:“常量”

    在 cuda.hpp 中, virtual void free(GpuMat* mat) = 0;   -> virtual void _free(GpuMat* mat) = 0;