本文共 1871 字,大约阅读时间需要 6 分钟。
10 121 21 31 42 52 65 63 73 87 84 94 109 10
2
3 31 22 31 3
0
题目中的景点相当于图中的点,道路相当于路径,当修一条路时候两个景点无法旅行,所以我们要通过修路来解决这个问题,让即使去掉一条边当前图依旧连通.也就是求在图中添加多少条边从而可以去掉任意边都依旧连通…
易知图中,边双连通分量之间,去掉任意一条边该连通分量依旧是连通的,所以可以求出连通图中边双连通分量的个数,然后缩点.最后统计叶子节点的个数,通过叶子结点获得应该增加多少条边.如果结点在一个边双连通分量中,则不需要添加边。而连通分量之间需要添加边,因此需要求解连通分量。
2.将每个双连通分量缩成点.
#include#include using namespace std;const int maxn = 1000 + 5;int n, m;int head[maxn], cnt;struct Edge{ int to, next;}e[maxn << 1];int low[maxn], dfn[maxn], degree[maxn], num;void add(int u, int v){ e[++cnt].next = head[u]; e[cnt].to = v; head[u] = cnt;}void tarjan(int u, int fa)//使用tarjan算法求出每个节点的low和dfn值{ dfn[u] = low[u] = ++num; for (int i = head[u]; i; i = e[i].next) { int v = e[i].to; if (v == fa) continue; if (!dfn[v]) { tarjan(v, u); low[u] = min(low[u], low[v]);//注:如果是求割点或割边则下边就开始进行判断. } else low[u] = min(low[u], dfn[v]); }}void init(){ memset(head, 0, sizeof(head)); memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(degree, 0, sizeof(degree)); cnt = num = 0;}int main(){ while (cin >> n >> m) { init(); int u, v; while (m--) { cin >> u >> v; add(u, v); add(v, u); } tarjan(1, 0); for (int u = 1; u <= n; u++) { for (int i = head[u]; i; i = e[i].next) { int v = e[i].to; if (low[u] != low[v])//对于每个连通分量命个名(以low命名)然后进行缩点, { degree[low[u]]++;//缩点 } } } int leaf = 0; for (int i = 1; i <= n; i++)//统计节点度数为1的个数 { if (degree[i] == 1) { leaf++; } } cout << (leaf + 1) / 2 << endl; } return 0;}
1.tarjan算法的使用
2.对于双连接图的理解.
转载地址:http://aufj.baihongyu.com/