题意:给定n个点m条边。要使任意两个点可以通过两条严格不同的路径到达。即边不能重复,点可以重复。求需要添加的最小边数

题目就是要求使这个图成为边双连通分量所需添加的最小边数。
我的做法:
将边双连通分量相关的点缩点。然后求出度为1的个数=num。答案就是(num+1)/2或者说是num/2+num%2
理由:度为1的肯定是叶子节点或者根节点。将叶子节点两两配对。如果是奇数的话就任意与一个节点配对成边即可。
我在做边双连通分量缩点的过程异常麻烦。
首先我求出桥,然后删掉这些桥。将连通块缩点(这些连通块是边双连通分量)。然后再计算度数。。写的很多。感觉很麻烦。肯定有更简短的代码。。

---------2014/7/11 在下面还有一个代码 修改过后的。。写法比前面这个简便多了。

//author: CHC
//First Edit Time: 2014-07-11 10:04
//Last Edit Time: 2014-07-11 11:53
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <algorithm>
using namespace std;
#define MAXN 5010
vector <int> e[MAXN];
vector <int> e1[MAXN];
vector <int> e2[MAXN];
int dfn[MAXN],low[MAXN],pre[MAXN],n,m;
int times=0,tot=0;
int du[MAXN];
void tarjan_3(int u){
dfn[u]=low[u]=++times;
for(int i=0;i<(int)e[u].size();i++){
int v=e[u][i];
if(!dfn[v]){
pre[v]=u;
tarjan_3(v);
low[u]=min(low[u],low[v]);
}
else if(pre[u]!=v){
low[u]=min(low[u],dfn[v]);
}
}
}
int vis[MAXN],tots;
void bfs(int u){
vis[u]=++tots;
queue <int> q;
q.push(u);
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=0;i<(int)e2[now].size();i++){
int next=e2[now][i];
if(vis[next])continue;
vis[next]=vis[now];
q.push(next);
}
}
}
bool check(int u,int v){
if(e1[u].empty())return true;
for(int i=0;i<(int)e1[u].size();i++){
int v1=e1[u][i];
if(v1==v)return false;
}
return true;
}
char has[MAXN];
void bfs1(int x){
queue <int> q;
q.push(x);
has[x]=1;
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=0;i<(int)e1[now].size();i++){
int next=e1[now][i];
if(has[next])continue;
has[next]=1;
++du[now];
++du[next];
q.push(next);
}
}
}
void solve(){
tots=times=tot=0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(pre,0,sizeof(pre));
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan_3(i);
//qiao
for(int i=1;i<=n;i++){
if(pre[i]>0&&dfn[pre[i]]<low[i]){
//cout<<pre[i]<<" "<<i<<endl;
e1[pre[i]].push_back(i);
e1[i].push_back(pre[i]);
}
}
for(int i=1;i<=n;i++){
for(int j=0;j<(int)e[i].size();j++){
int v=e[i][j];
if(check(i,v)){
e2[i].push_back(v);
e2[v].push_back(i);
}
}
}
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
if(!vis[i]){
bfs(i);
}
}
memset(du,0,sizeof(du));
for(int i=0;i<n+10;i++)e1[i].clear();
for(int i=1;i<=n;i++){
for(int j=0;j<(int)e[i].size();j++){
int v=e[i][j];
if(vis[i]==vis[v])continue;
e1[vis[i]].push_back(vis[v]);
e1[vis[v]].push_back(vis[i]);
//printf("%d-->%d\n",vis[i],vis[v]);
}
}
memset(has,0,sizeof(has));
for(int i=1;i<=tots;i++)
if(!has[i])bfs1(i);
int cnt=0;
for(int i=1;i<=tots;i++){
//printf("%d: %d\n",i,du[i]);
if(du[i]==1)++cnt;
}
//printf("tots:%d\n",tots);
//printf("cnt:%d\n",cnt);
printf("%d\n",(cnt+1)/2);
return ;
}

int main()
{
//freopen("out.txt","r",stdin);
//freopen("out-2.txt","w",stdout);
while(~scanf("%d%d",&n,&m)){
for(int i=0;i<n+10;i++)e[i].clear();
for(int i=0;i<n+10;i++)e1[i].clear();
for(int i=0;i<n+10;i++)e2[i].clear();
for(int i=0,x,y;i<m;i++){
scanf("%d%d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
}
solve();
}
return 0;
}

代码二:

//author: CHC
//First Edit Time: 2014-07-11 15:40
//Last Edit Time: 2014-07-11 16:26
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <algorithm>
using namespace std;
#define MAXN 5010
struct Edge
{
int to,next;
bool vis,bge;
}edge[MAXN*2];
int dfn[MAXN],low[MAXN],pre[MAXN];
int sta[MAXN],bleg[MAXN];
int times,n,m,top;
int tot,head[MAXN];
void Add(int u,int v){
edge[tot].to=v;
edge[tot].next=head[u];
edge[tot].vis=false;
edge[tot].bge=false;
head[u]=tot++;
}
void tarjan_3(int u){
dfn[u]=low[u]=++times;
sta[++top]=u;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(edge[i].vis)continue;
edge[i].vis=edge[i^1].vis=true;
if(!dfn[v]){
pre[v]=u;
tarjan_3(v);
low[u]=min(low[u],low[v]);
}
else if(!bleg[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
bleg[0]++;
do{
bleg[sta[top]]=bleg[0];
}while(sta[top--]!=u);
bleg[u]=bleg[0];
}
}
int du[MAXN];
void solve(){
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(pre,0,sizeof(pre));
memset(bleg,0,sizeof(bleg));
memset(du,0,sizeof(du));
top=times=0;
for(int i=1;i<=n;i++)
if(!dfn[i]){
tarjan_3(i);
}
for(int i=0;i<tot;i++){
if(edge[i].bge)continue;
int u=edge[i].to;
int v=edge[i^1].to;
if(pre[v]==u&&dfn[u]<low[v]){
edge[i].bge=edge[i^1].bge=true;
}
}
for(int i=1;i<=n;i++){
for(int j=head[i];j!=-1;j=edge[j].next){
int v=edge[j].to;
if(bleg[i]==bleg[v])continue;
++du[bleg[i]];
}
}
int cnt=0;
for(int i=1;i<=bleg[0];i++){
if(du[i]==1)++cnt;
}
printf("%d\n",(cnt+1)/2);
}
int main()
{
while(~scanf("%d%d",&n,&m)){
tot=0;
memset(head,-1,sizeof(head));
for(int i=0,x,y;i<m;i++){
scanf("%d%d",&x,&y);
Add(x,y);
Add(y,x);
}
solve();
}
return 0;
}