poj 3352
题意:一个连通的无向图,求至少需要添加几条边,救能保证删除任意一条边,图仍然是连通的。
思路:边的双连通图。其实就是要求至少添加几条边,可以使整个图成为一个边双连通图。用tarjan算法(求割点割边)求出low数组,这里可以简化,然 后依据“low相同的点在一个边连通分量中”,缩点之后构造成树(这里可以直接利用low[]数组,low[i]即为第i节点所在的连通分量的标号)。求 出树中出度为1的节点数left,答案即为(leaf+1)/2。
代码:
#include<iostream>
#include<fstream>
using namespace std;
int n,m;
struct e{
int data;
e *next;
};
e edge[1001];
int in[1001],dfn[1001],sta[1001],low[1001],scc[1001];
int top,index,sum;
void tar(int s,int f){
int i,j,k;
low[s]=dfn[s]=++index;
sta[++top]=s;
e *p=edge[s].next;
while(p){
if(p->data==f)
{
p=p->next;
continue;
}
if(dfn[p->data]==0)
{
tar(p->data,s);
low[s]=min(low[s],low[p->data]);
}
else
low[s]=min(low[s],dfn[p->data]);
p=p->next;
}
if(low[s]==dfn[s])
{
sum++;
do{
i=sta[top--];
scc[i]=sum;
}while(i!=s);
}
}
void solve(){
int i,j,k;
index=0;sum=0;
memset(dfn,0,sizeof(dfn));
memset(in,0,sizeof(in));
for(i=1;i<=n;i++)
if(dfn[i]==0)
tar(i,0);
for(i=1;i<=n;i++)
{
e *p=edge[i].next;
while(p){
if(scc[p->data]!=scc[i])
{
in[scc[p->data]]++;
in[scc[i]]++;
}
p=p->next;
}
}
j=0;
for(i=1;i<=sum;i++)
if(in[i]==2)
j++;
cout<<(j+1)/2<<endl;
}
void read(){
// ifstream cin("in.txt");
int i,j,k,s,t;
while(cin>>n>>m)
{
for(i=1;i<=n;i++)
edge[i].next=0;
for(i=1;i<=m;i++)
{
cin>>s>>t;
e *p=new e;
p->data=t;
p->next=edge[s].next;
edge[s].next=p;
e *q=new e;
q->data=s;
q->next=edge[t].next;
edge[t].next=q;
}
solve();
}
}
int main(){
read();
return 0;
}
浙公网安备 33010602011771号