hdu 4635 Strongly connected Kosaraju/Tarjan求强联通分量大小
来源:互联网 发布:淘宝上哪家卖红酒靠谱 编辑:程序博客网 时间:2024/06/01 10:19
hdu 4635 Strongly connected Kosaraju/Tarjan求强联通分量
题目链接: hdu 4635 Strongly connected
题意: 给定N个顶点M条边的有向图。问,在保证这个图不是强连通图的情况下,最多可以增加多少条有向边。如果原图本身就是连通的,则输出-1。
分析:原图由多个强连通分量构成,要加边尽可能尽可能最多,然后图不是强连通的,我可以这么考虑加边的步骤:
- 在每一个强连通分量中继续增加边, 一直到不能再增加(加满整个强连通分量),可以让原图依旧不是强连通。
- 加完边之后,我们再来考虑缩点构成的DAG图。假设DAG中有K个顶点,那么,我可以选出(K-1)个缩点,在他们之间加边变成一个强连通分量,这样保证整个图中还剩下两个强连通分量。
- 对于剩下的两个强连通分量,我还可以加边,就是单向加边,依旧保证了图不是强连通图。
总结一下上面的步骤:可以把第一二步合并,就是原图中的K个强连通分量中,将他们分成两个部分,形成新的两个强连通分量X,Y,设这两个强连通分量中的顶点个数分别为x, y,有x+y=N, 那么将这两个强连通分量内部连满边,总边数依次就是x*(x-1)、 y*(y-1), 第三步,向A,B两个强连通分量中添加边,最多可以添加x*y个。那么,图中总共的边数就是
x*(x-1)+y*(y-1)+x*y = x^2+y^2-(x+y)-xy = N^2-N-x*(N-x),
显然x 与(N-x)差距最大的时候,边数最多。
那么,我们只需要从原图K个强连通分量中选出含顶点最少并且入度或者出度为0的一个强连通分量就好了。然后结果就是 N^2-N-x*(N-x)-M。为什么要缩点的入度或者出度为0呢?你画出DAG就知道了~~~
首先用Kosaraju/Tarjan算法对图进行缩点,并同时保存原图中每个强连通分量的大小。然后对强连通分量按照大小排序。选出含顶点最少并且入度或者出度为0的一个强连通分量。然后就求出答案了。
/** * Kosaraju 算法 */#include <set>#include <cmath>#include <queue>#include <vector>#include <cstdio>#include <string>#include <cstring>#include <iomanip>#include <iostream>#include <algorithm>using namespace std;#define FIN freopen("input.txt","r",stdin)#define FOUT freopen("output.txt","w",stdout)#define fst first#define snd secondtypedef __int64LL;typedef pair<int, int>PII;const int MAXN = 100000 + 5;const int MAXM = 100000 + 5;struct Edge {int v, next;Edge() {}Edge(int v, int next) : v(v), next(next) {}};struct Graph {Edge edge[MAXN];int head[MAXN], tot;void init() {tot = 0;memset(head, -1, sizeof(head));}void add_edge(int u, int v) {edge[tot] = Edge(v, head[u]);head[u] = tot++;}} G1, G2;int order[MAXN], Index;int block[MAXN];int cnt[MAXN], r[MAXN];bool iFlag[MAXN], oFlag[MAXN];bool vis[MAXN];int T, N, M;LL res;bool cmp(const int& a, const int& b) {return cnt[a] < cnt[b];}void dfs1(int u) {int v;vis[u] = true;for (int i = G1.head[u]; ~i; i = G1.edge[i].next) {v = G1.edge[i].v;if (!vis[v]) dfs1(v);}order[++Index] = u;}void dfs2(int u, int k) {int v;vis[u] = true;block[u] = k;cnt[k] ++;for (int i = G2.head[u]; ~i; i = G2.edge[i].next) {v = G2.edge[i].v;if (!vis[v]) dfs2(v, k);}}int scc() {Index = 0;memset(vis, false, sizeof(vis));for (int i = 1; i <= N; i++) {if (!vis[i]) dfs1(i);}memset(vis, false, sizeof(vis));memset(cnt, 0, sizeof(cnt));memset(iFlag, false, sizeof(iFlag));memset(oFlag, false, sizeof(oFlag));int u, k = 0;for (int i = Index; i > 0; i--) {u = order[i];if (!vis[u]) {dfs2(u, ++k);}}return k;}set<PII> input;int main() {#ifndef ONLINE_JUDGEFIN;#endif // ONLINE_JUDGEint u, v, cas = 0;scanf("%d", &T);while (T--) {G1.init();G2.init();input.clear();scanf("%d %d", &N, &M);for (int i = 0; i < M; i ++) {scanf("%d %d", &u, &v);int t1 = input.size();input.insert(make_pair(u, v));int t2 = input.size();if (t1 == t2) {i --;M --;continue;}G1.add_edge(u, v);G2.add_edge(v, u);}int k = scc();printf("Case %d: ", ++cas);if (k == 1) {puts("-1");continue;}for (int i = 1; i <= k; i++) r[i] = i;sort(r + 1, r + k + 1, cmp);int x;for (set<PII>::iterator iter = input.begin(); iter != input.end(); iter++) {u = (*iter).fst;v = (*iter).snd;if (block[u] == block[v]) continue;oFlag[block[u]] = true;iFlag[block[v]] = true;}for (int i = 1; i <= k; i++) {int j = r[i];if (!iFlag[j] || !oFlag[j]) {x = cnt[j];break;}}res = (LL)N * (LL)N - N - (LL) x * (LL)(N - x) - M;printf("%I64d\n", res);}return 0;}
/** * Tarjan 算法 */#include <set>#include <cmath>#include <queue>#include <vector>#include <cstdio>#include <string>#include <cstring>#include <iomanip>#include <iostream>#include <algorithm>using namespace std;#define FIN freopen("input.txt","r",stdin)#define FOUT freopen("output.txt","w",stdout)#define fst first#define snd secondtypedef __int64LL;typedef pair<int, int>PII;const int MAXN = 100000 + 5;const int MAXM = 100000 + 5;struct Edge {int v, next;Edge() {}Edge(int v, int next) : v(v), next(next) {}} edge[MAXN];int head[MAXN], tot;int low[MAXN], dfn[MAXN], stack[MAXN], belong[MAXN];int cnt[MAXN], r[MAXN];int Index, top;int scc;bool inStack[MAXN];bool iFlag[MAXN], oFlag[MAXN];int T, M, N;set<PII> input;bool cmp(const int& a, const int& b) {return cnt[a] < cnt[b];}void add_edge(int u, int v) {edge[tot] = Edge(v, head[u]);head[u] = tot++;}void Tarjan(int u) {int v;low[u] = dfn[u] = ++Index;stack[top++] = u;inStack[u] = true;for (int i = head[u]; ~i; i = edge[i].next) {v = edge[i].v;if (!dfn[v]) {Tarjan(v);low[u] = min(low[u], low[v]);} else if (inStack[v] && low[u] > dfn[v]) {low[u] = dfn[v];}}if (low[u] == dfn[u]) {scc ++;do {v = stack[--top];inStack[v] = false;belong[v] = scc;cnt[scc] ++;} while (v != u);}}void init() {input.clear();scc = top = Index = tot = 0;memset(head, -1, sizeof(head));memset(inStack, false, sizeof(inStack));memset(cnt, 0, sizeof(cnt));memset(dfn, 0, sizeof(dfn));memset(iFlag, false, sizeof(iFlag));memset(oFlag, false, sizeof(oFlag));}int main() {#ifndef ONLINE_JUDGEFIN;#endif // ONLINE_JUDGEint u, v, cas = 0;scanf("%d", &T);while (T--) {init();scanf("%d %d", &N, &M);for (int i = 0; i < M; i ++) {scanf("%d %d", &u, &v);PII e = make_pair(u, v);if (input.find(e) == input.end()) {input.insert(e);add_edge(u, v);} else {i --;M --;}}printf("Case %d: ", ++cas);for (int i = 1; i <= N; i++) {if (!dfn[i]) Tarjan(i);}if (scc == 1) {puts("-1");continue;}for (set<PII>::iterator iter = input.begin(); iter != input.end(); iter++) {u = (*iter).fst, v = (*iter).snd;if (belong[u] != belong[v]) {oFlag[belong[u]] = true;iFlag[belong[v]] = true;}}for (int i = 1; i <= scc; i++) r[i] = i;sort(r + 1, r + scc + 1, cmp);int x;for (int i = 1, j; i <= scc; i++) {j = r[i];if (!iFlag[j] || !oFlag[j]) {x = cnt[j];break;}}LL res = (LL)N * N - N - (LL)x * (N - x) - M;printf("%I64d\n", res);}return 0;}
1 0
- hdu 4635 Strongly connected Kosaraju/Tarjan求强联通分量大小
- hdu 4635 Strongly connected(强联通分量+缩
- hdu 4635 Strongly connected (tarjan强连通分量)
- hdu 4635 Strongly connected(强联通)
- hdu 4635 Strongly connected (强连通分量)
- hdu-4635-Strongly connected-强连通分量
- HDU 4635 Strongly connected(强连通分量)
- HDU 4635 Strongly connected(强连通分量)
- HDOJ 4635 - Strongly connected/2013多校联合第四场D Tarjan求强联通图.缩点.
- hdu 4635 Strongly connected (强连通分量缩点)
- HDU 4635 Strongly connected(强连通分量+缩点)
- HDU 4635 Strongly connected 强连通分量分解
- HDU-4635-Strongly connected(强连通分量)
- hdu 4635 Strongly connected(Tarjan)
- hdu 4635 Strongly connected (tarjan)
- [tarjan] hdu 4635 Strongly connected
- tarjan求强联通分量
- tarjan求强联通分量
- 通过JPcap捕获网络TCP数据包,并将解析的信息写入execl文件中
- tjut 4940
- JavaSE学习笔记之-----数组
- VS2013中的getch()和scanf()报错问题
- 【杭电2098】分拆素数和
- hdu 4635 Strongly connected Kosaraju/Tarjan求强联通分量大小
- MySQL配置
- OC编码风格
- 图片处理类(剪裁、缩放、水印)
- 二叉树层遍历
- Java Exchange企业邮件服务器 发Email
- DZ迁移
- HDU5120 Intersection 相交环总面积 (2014北京现场赛) 两圆香蕉模板
- 坦克大战_我方坦克发射子弹