这是一道求边双连通分量的题目,比较基础,适合刚学过相关算法的人做。题目说的有点花哨,不过基本意思就是如果任意两个点之间至少有两条不同的路径,该添加多少条边。
至于为什么是用边双连通分量的算法,我也不是很清楚,因为我也是刚接触这种题,所以我只有根据这道题推测一下:边双连通分量简单来说就是一个没有割边的连通分量,所以当找到一条A点到B点的路径是,删除路径的一条边,一定还有另一条路径可以从A点到B点,因为图中无割边,删一条边不会使图不连通。希望各位大神如果发现我的解释有问题,请告诉我一下!
大体思路:首先求边双连通分量,感觉这个边双连通分量的算法很像求强连通的算法,只不过在更新dfn数组和low数组时有限制,不能用父节点来更新low值。然后将一个边双连通分量缩为一点,并注意转移其相关边的连接关系,当然并不需要真的缩点,具体看代码理解一下。缩点之后的图是一棵树,计算一下叶节点的个数n,那么答案就是(n+1)/2。具体原因可以画图理解一下,按照叶节点是奇数还是偶数分情况讨论一下。此外,根据low值是否相等判断是否属于同一个边双连通分量。
最后还要补充一下,这道题的图有重边,要去掉重边。(估计是因为这句话“There might already be more than one paths between the same pair of fields, and you may also build a new path that connects the same fields as some other path”。而这里的“the same pair of fields”,是指一条边直接连接的两个区域,所以可以直接去除重边,不加考虑)
参考博文:poj3177-tarjan求桥/割边。
代码(C++):
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define MAXp 5009
#define MAXe (10000*2+9)
using namespace std;
//#define LOCAL
struct Edge{
int u;
int v;
int next;
} edge[MAXe];
int head[MAXp],dfn[MAXp],low[MAXp],c,ts,odeg[MAXp];
bool map[MAXp][MAXp];
void addEdge(int u,int v)
{
edge[c].u=u;
edge[c].v=v;
edge[c].next=head[u];
head[u]=c;
c++;
}
void dfs(int u,int pre)
{
int i,v;
dfn[u]=low[u]=++ts;
for(i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(!dfn[v])
{
dfs(v,u);
low[u]=min(low[v],low[u]);
}else if(v!=pre) low[u]=min(dfn[v],low[u]);
}
}
int solve(int f)
{
int i,u,v,ans;
memset(odeg,0,sizeof(odeg));
ans=0;
for(i=0;i<c;i++)
{
u=edge[i].u;
v=edge[i].v;
if(low[u]!=low[v]) odeg[low[u]]++;
}
for(i=1;i<=f;i++) if(odeg[i]==1) ans++;
ans=(ans+1)/2;
return ans;
}
int main(int argc, char *argv[])
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int r,f,a,b,i;
while(scanf("%d %d",&f,&r)!=EOF)
{
c=0;
memset(head,-1,sizeof(head));
memset(map,true,sizeof(map));
for(i=0;i<r;i++)
{
scanf("%d %d",&a,&b);
if(map[a][b]&&map[b][a])
{
addEdge(a,b);
addEdge(b,a);
map[a][b]=map[b][a]=false;
}
}
ts=0;
memset(dfn,0,sizeof(dfn));
dfs(1,-1);
printf("%d\n",solve(f));
}
system("PAUSE");
return EXIT_SUCCESS;
}
题目(http://poj.org/problem?id=3177):
Time Limit: 1000MS | Memory Limit: 65536K | |
Description
Given a description of the current set of R (F-1 <= R <= 10,000) paths that each connect exactly two different fields, determine the minimum number of new paths (each of which connects exactly two fields) that must be built so that there are at least two separate routes between any pair of fields. Routes are considered separate if they use none of the same paths, even if they visit the same intermediate field along the way.
There might already be more than one paths between the same pair of fields, and you may also build a new path that connects the same fields as some other path.
Input
Lines 2..R+1: Each line contains two space-separated integers which are the fields at the endpoints of some path.
Output
Sample Input
7 7 1 2 2 3 3 4 2 5 4 5 5 6 5 7
Sample Output
2
Hint
One visualization of the paths is:
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:
1 – 2: 1 –> 2 and 1 –> 6 –> 5 –> 2
1 – 4: 1 –> 2 –> 3 –> 4 and 1 –> 6 –> 5 –> 4
3 – 7: 3 –> 4 –> 7 and 3 –> 2 –> 5 –> 7
Every pair of fields is, in fact, connected by two routes.
It's possible that adding some other path will also solve the problem (like one from 6 to 7). Adding two paths, however, is the minimum.