标签:bin single 连通块 iat condition miss node iss new
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 10798 | Accepted: 4626 |
Description
Input
Output
Sample Input
7 7 1 2 2 3 3 4 2 5 4 5 5 6 5 7
Sample Output
2
Hint
1 2 3 +---+---+ | | | | 6 +---+---+ 4 / 5 / / 7 +Building new paths from 1 to 6 and from 4 to 7 satisfies the conditions.
1 2 3 +---+---+ : | | : | | 6 +---+---+ 4 / 5 : / : / : 7 + - - - -Check some of the routes:
下面解析来自:女神的博客
斌神博客上有个不错的总结:斌神的博客
大致题意:
为了保护放牧环境,避免牲畜过度啃咬同一个地方的草皮,牧场主决定利用不断迁移牲畜进行喂养的方法去保护牧草。然而牲畜在迁移过程中也会啃食路上的牧草,所以假设每次迁移都用同一条道路,那么该条道路相同会被啃咬过度而遭受破坏。
如今牧场主拥有F个农场。已知这些农场至少有一条路径连接起来(不一定是直接相连)。但从某些农场去另外一些农场。至少有一条路可通行。为了保护道路上的牧草,农场主希望再建造若干条道路,使得每次迁移牲畜时,至少有2种迁移途径,避免反复走上次迁移的道路。
已知当前有的R条道路。问农场主至少要新建造几条道路,才干满足要求?
解题思路:
“使得每次迁移牲畜时,至少有2种迁移途径,避免反复走上次迁移的道路。”就是说当吧F个农场看作点、路看作边构造一个无向图G时,图G不存在桥。
那么能够建立模型:
给定一个连通的无向图G,至少要加入几条边。才干使其变为双连通图。
当图G存在桥(割边)的时候,它必然不是双连通的。桥的两个端点必然分别属于图G的两个【边双连通分量】。一旦删除了桥,这两个【边双连通分量】必然断开,图G就不连通了。可是假设在两个【边双连通分量】之间再加入一条边。桥就不再是桥了。这两个【边双连通分量】之间也就是双连通了。
那么假设图G有多个【边双连通分量】呢?至少应该加入多少条边,才干使得随意两个【边双连通分量】之间都是双连通(也就是图G是双连通的)
1、 首先要找出图G的全部【边双连通分量】。
2、 把每个【边双连通分量】都看做一个点(即【缩点】)
3、 问题再次被转化为“至少在缩点树上添加多少条树边。使得这棵树变为一个双连通图”。
首先知道一条等式:
若要使得随意一棵树。在添加若干条边后。变成一个双连通图,那么
至少添加的边数 =( 这棵树总度数为1的结点数 + 1 )/ 2。
#include <cstdio> #include <cstring> #include <algorithm> #include <stack> #define maxn 5010 #define maxm 20010 using namespace std; int n, m; struct node { int u, v, next; }; node edge[maxm]; //缩点后形成树,每一个点的度数 int du[maxn]; int head[maxn], cnt; int low[maxn], dfn[maxn]; //Belong数组的值是 1 ~ ebc_block int Stack[maxn], Belong[maxn]; int ebc_block;//边双连通块数 int dfs_clock; int top;//模拟栈的指针 bool Instack[maxn]; void init(){ cnt = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v){ edge[cnt] = {u, v, head[u]}; head[u] = cnt++; } void getmap(){ while(m--){ int a, b; scanf("%d%d", &a, &b); addedge(a, b); addedge(b, a); } } void tarjan(int u, int pre){ int v; low[u] = dfn[u] = ++dfs_clock; Stack[top++] = u; Instack[u] = true; int have = 1; for(int i = head[u]; i != -1; i = edge[i].next){ v = edge[i].v; if(have && v == pre){//去重边 have = 0; continue; } if(!dfn[v]){ tarjan(v, u); low[u] = min(low[u], low[v]); } else if(Instack[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]){ ebc_block++; do{ v = Stack[--top]; Instack[v] = false; Belong[v] = ebc_block; } while(v != u); } } void suodian(){ memset(du, 0, sizeof(du)); for(int i = 0; i < cnt; i += 2 ){ int u = Belong[edge[i].u]; int v = Belong[edge[i].v]; if(u != v) du[u]++, du[v]++; } } void find(){ memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(Instack, false, sizeof(Instack)); memset(Belong, 0, sizeof(Belong)); dfs_clock = 0; ebc_block = 0; top = 0; tarjan(1, -1);//连通图 } void solve(){ int ans = 0; if(ebc_block == 1){ printf("0\n"); return ; } for(int i = 1; i <= ebc_block; ++i) if(du[i] == 1) ans++; printf("%d\n", (ans + 1) / 2); } int main (){ while(scanf("%d%d", &n, &m) != EOF){ init(); getmap(); find(); suodian(); solve(); } return 0; }
POJ 3177--Redundant Paths【无向图添加最少的边成为边双连通图 && tarjan求ebc && 缩点构造缩点树】
标签:bin single 连通块 iat condition miss node iss new
原文地址:http://www.cnblogs.com/cynchanpin/p/7094216.html