HDU 4635 Strongly connected(强连通分量+缩点)
2015-09-21 20:50
197 查看
题意:给出一个简单有向图,问最多添加多少边使得这个图连通并且不强连通。
思路:考虑这样一个问题,要使得这个图不强连通并且边数最多
那么最后一定是将这个图这个图分为两个强连通分量且这两个子图都是完全图,并且这两个强连通分量中任意两点都有且只有一条有向边,假设这两个强连通分量中各有a,b个结点,那么答案就是n*(n-1)-a*b,
那么我们只需要将这个图分为两个强连通分量且这两个强连通分量中结点数的差尽量大,并且不难想到,这两个强连通分量中一定有一个是拓扑序最大或最小的,那么我们只需要求出入度或出度为0的结点数最少的强连通分量即可。
思路:考虑这样一个问题,要使得这个图不强连通并且边数最多
那么最后一定是将这个图这个图分为两个强连通分量且这两个子图都是完全图,并且这两个强连通分量中任意两点都有且只有一条有向边,假设这两个强连通分量中各有a,b个结点,那么答案就是n*(n-1)-a*b,
那么我们只需要将这个图分为两个强连通分量且这两个强连通分量中结点数的差尽量大,并且不难想到,这两个强连通分量中一定有一个是拓扑序最大或最小的,那么我们只需要求出入度或出度为0的结点数最少的强连通分量即可。
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<map> #include<set> #include<ctime> #define eps 1e-6 #define LL long long #define pii pair<int, int> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int MAXN = 100100; const int INF = 0x3f3f3f3f; //强连通分量 int n, m; int indu[MAXN], outdu[MAXN], num[MAXN]; vector<int> G[MAXN]; int pre[MAXN], lowlink[MAXN], sccno[MAXN], dfs_clock, scc_cnt; stack<int> S; void dfs(int u) { pre[u] = lowlink[u] = ++dfs_clock; S.push(u); for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(!pre[v]) { dfs(v); lowlink[u] = min(lowlink[u], lowlink[v]); } else if(!sccno[v]) { lowlink[u] = min(lowlink[u], pre[v]); } } if(lowlink[u] == pre[u]) { scc_cnt++; for(;;) { int x = S.top(); S.pop(); sccno[x] = scc_cnt; if(x == u) break; } } } void find_scc() { dfs_clock = scc_cnt = 0; memset(sccno, 0, sizeof(sccno)); memset(pre, 0, sizeof(pre)); for(int i = 1; i <= n; i++) if(!pre[i]) dfs(i); } void init() { for(int i = 1; i <= n; i++) G[i].clear(); memset(indu, 0, sizeof(indu)); memset(outdu, 0, sizeof(outdu)); memset(num, 0, sizeof(num)); } int main() { //freopen("input.txt", "r", stdin); int T; cin >> T; int kase = 0; while(T--) { scanf("%d%d", &n, &m); init(); for(int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); G[u].push_back(v); } find_scc(); for(int i = 1; i <= n; i++) { num[sccno[i]]++; for(int j = 0; j < G[i].size(); j++) { int v = G[i][j]; if(sccno[i] != sccno[v]) indu[sccno[v]]++, outdu[sccno[i]]++; } } int tmp = INF; for(int i = 1; i <= scc_cnt; i++) { if(!outdu[i]) tmp = min(num[i], tmp); if(!indu[i]) tmp = min(num[i], tmp); } LL ans = (LL)n*(n-1) - (LL)tmp*(n-tmp) - m; if(scc_cnt == 1) printf("Case %d: -1\n", ++kase); else printf("Case %d: %I64d\n", ++kase, ans); } return 0; }
相关文章推荐
- gcc下fflush(stdin)无效的解决
- C#软件开发实例.私人订制自己的屏幕截图工具(二)创建项目、注册热键、显示截图主窗口
- 【wireshark】插件开发(一):概述
- 加载动态设计--等待的艺术创作思维
- 省级选择器
- 《剑指Offer》面试题:栈的压入弹出序列是否匹配
- 马哥Linux运维笔记----2
- 黑马程序员--多线程
- [codevs3862]竞赛班的垃圾处理(刷水) 没写的少年去倒垃圾吧
- 网页设计师该向印刷设计学习的3个规则
- 输入法切换不了
- javaWeb验证码
- PAT(A)1002
- C#软件开发实例.私人订制自己的屏幕截图工具(一)功能概览
- 黑马程序员--接口
- 【IOS 开发学习总结-OC-13】★★objective-c面向对象之——KVC(键值编码)
- 【Python之旅】第二篇(九):迭代器
- ZOJ1414题的解法
- 欢迎大家来我的博客园踩踩~~
- 现实与理想的辩证关系