[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(反之 ...
随机推荐
- js实现活动倒计时
let startTime = 1527647143949; // 开始时间 var time = new Countdown('timer',startTime); function Countdo ...
- [LeetCode] Rank Scores -- 数据库知识(mysql)
Write a SQL query to rank scores. If there is a tie between two scores, both should have the same ra ...
- python_内置函数1_42
内置函数 内置函数大全: Built-in Functions abs() dict() help() min() setattr() all() dir() hex() next() ...
- BeautifulSoup库
'''灵活又方便的网页解析库,处理高效,支持多种解析器.利用它不用编写正则表达式即可方便的实现网页信息的提取.''' BeautifulSoup库包含的一些解析库: 解析库 使用方法 优势 劣势 py ...
- Misha, Grisha and Underground CodeForces - 832D (倍增树上求LCA)
Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations ...
- js总结:JavaScript入门
1. JavaScript-输出内容(document.write) 2.在html中引用js文件 3.定义变量 语法:var 变量名 说明: ⑴变量必须使用字母.下划线(_)或者美元符($)开始. ...
- 【学习总结】Git学习-参考廖雪峰老师教程二-安装Git
学习总结之Git学习-总 目录: 一.Git简介 二.安装Git 三.创建版本库 四.时光机穿梭 五.远程仓库 六.分支管理 七.标签管理 八.使用GitHub 九.使用码云 十.自定义Git 期末总 ...
- Linux 典型应用之缓存服务
memcached 安装和简单使用 yum install memcached 启动 -d 表示以守护进程的方式启动 memcached -d 安装telnet 它可以检测某个端口是否是通的,可以发送 ...
- Git之项目使用
现在最为盛行的版本控制器,非git莫属了, 那就看看在项目中我们是如何使用它的吧 一. 在已经存在秘钥对的情况下,我们需要在本地进行相关配置 git config --global user.name ...
- java的编程习惯影响程序性能
在Java程序中,性能问题的大部分原因并不在于Java语言,而是在于程序本身. 养成良好的编程习惯非常重要,能够显著地提升程序性能. 尽量在合适的场合使用单例 使用单例可以减轻加载的负担,缩短加载的时 ...