// tarjan算法求无向图的割点、点双连通分量并缩点
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int SIZE = 100010;
int head[SIZE], ver[SIZE * 2], Next[SIZE * 2];
int dfn[SIZE], low[SIZE], stack[SIZE], new_id[SIZE], c[SIZE];
int n, m, tot, num, root, top, cnt, tc;
bool cut[SIZE];
vector<int> dcc[SIZE];
int hc[SIZE], vc[SIZE * 2], nc[SIZE * 2]; void add(int x, int y) {
ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
} void add_c(int x, int y) {
vc[++tc] = y, nc[tc] = hc[x], hc[x] = tc;
} void tarjan(int x) {
dfn[x] = low[x] = ++num;
stack[++top] = x;
if (x == root && head[x] == 0) { // 孤立点
dcc[++cnt].push_back(x);
return;
}
int flag = 0;
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if (!dfn[y]) {
tarjan(y);
low[x] = min(low[x], low[y]);
if (low[y] >= dfn[x]) {
flag++;
if (x != root || flag > 1) cut[x] = true;
cnt++;
int z;
do {
z = stack[top--];
dcc[cnt].push_back(z);
} while (z != y);
dcc[cnt].push_back(x);
}
}
else low[x] = min(low[x], dfn[y]);
}
} int main() {
cin >> n >> m;
tot = 1;
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
if (x == y) continue;
add(x, y), add(y, x);
}
for (int i = 1; i <= n; i++)
if (!dfn[i]) root = i, tarjan(i);
for (int i = 1; i <= n; i++)
if (cut[i]) printf("%d ", i);
puts("are cut-vertexes");
for (int i = 1; i <= cnt; i++) {
printf("v-DCC #%d:", i);
for (int j = 0; j < dcc[i].size(); j++)
printf(" %d", dcc[i][j]);
puts("");
}
// 给每个割点一个新的编号(编号从cnt+1开始)
num = cnt;
for (int i = 1; i <= n; i++)
if (cut[i]) new_id[i] = ++num;
// 建新图,从每个v-DCC到它包含的所有割点连边
tc = 1;
for (int i = 1; i <= cnt; i++)
for (int j = 0; j < dcc[i].size(); j++) {
int x = dcc[i][j];
if (cut[x]) {
add_c(i, new_id[x]);
add_c(new_id[x], i);
}
else c[x] = i; // 除割点外,其它点仅属于1个v-DCC
}
printf("缩点之后的森林,点数 %d,边数 %d\n", num, tc / 2);
printf("编号 1~%d 的为原图的v-DCC,编号 >%d 的为原图割点\n", cnt, cnt);
for (int i = 2; i < tc; i += 2)
printf("%d %d\n", vc[i ^ 1], vc[i]);
}

最新文章

  1. Titanium.UI.createAlertDialog
  2. NCBI database download
  3. SQL Server 分区表
  4. watch监听 chechbox 全选
  5. (实用篇)php处理单文件、多文件上传代码分享
  6. css3 div垂直居中
  7. 类的特殊成员&amp;反射&amp;异常处理
  8. 从零开始学安全(三)●黑客常用的windows端口
  9. Java多线程(六)——线程让步
  10. Spring Boot 之整合 EasyUI 打造 Web 应用
  11. docker安装后启动出现错误
  12. ubuntu安装jupyter 并设置远程访问
  13. 图片和span水平垂直居中
  14. 数据分析与展示---Matplotlib入门
  15. LINUX block I/O --systemtap
  16. Java之JVM逃逸分析
  17. 使用MongoDB血泪般的经验教训
  18. eclipse中误删tomcat后,文件都报错,恢复server时无法选择tomcat7.0解决办法
  19. 用firebug 进行表单自定义提交
  20. Java字符串拆分和字符串连接

热门文章

  1. 使用tap、Fragment等相关相关知识点。实现类似微信的界面
  2. Java第七天,类的继承
  3. 抓包工具fiddler安装和配置
  4. "视频播放器"组件:&lt;video-player&gt; —— 快应用组件库H-UI
  5. 关于在React中 报Super expression must either be null or a function, not undefined (采坑系列)
  6. windows powershell校验下载的文件MD5和SHA1值
  7. 小程序—银行、券商们下一代APP的进阶方向
  8. Spring Boot 集成 Spring Security 入门案例教程
  9. 跑Linux内存占用率的shell脚本
  10. 分析PE