题目来源:http://codeforces.com/gym/100712/attachments
先用tarjan找出所有桥,计数。
tarjan得到的树另存,如果边是桥,那么边权为1,否则为0。
跑两次dfs得到树的直径(权值最大),用桥的总数-直径的值,即为结果。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m;
int cnt=0;
const int maxn=1e5+10;
struct data{int to,next;}e[maxn*2];
int head[maxn];
void ins(int x,int y)
{
e[++cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt;
}
int dfn[maxn],low[maxn];
bool vis[maxn];
int cur=0;
int tot=0;
/***********************************/
int _cnt=0;
int _head[maxn];
struct edge{int to,next,vi;}_e[maxn*2];
void _ins(int x,int y,int z)
{
_e[++_cnt].to=y;
_e[_cnt].next=_head[x];
_e[_cnt].vi=z;
_head[x]=_cnt;
}
int f[maxn];
void dfs(int x)
{
vis[x]=1;
for(int i=_head[x];i;i=_e[i].next)
{
if(vis[_e[i].to]==0)
{
f[_e[i].to]=f[x]+_e[i].vi;
dfs(_e[i].to);
}
}
}
/************/
void tarjan(int u,int fa)
{
low[u]=dfn[u]=++cur;
vis[u]=1;
for(int i=head[u];i;i=e[i].next)
{
int x=e[i].to;
if(x==fa)continue;
if(dfn[x]==0)tarjan(x,u);
if(vis[x]&&low[u]>low[x])low[u]=low[x];
}
if(dfn[u]==low[u])
{
if(fa!=0)
{
tot++;
_ins(fa,u,1);
_ins(u,fa,1);
}
}
else
{
if(fa!=0)
{
_ins(fa,u,0);
_ins(u,fa,0);
}
}
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int _;cin>>_;
while(_--)
{
cin>>n>>m;
cnt=0;cur=0;tot=0;
memset(head,0,sizeof(head));
int x,y;
for(int i=1;i<=m;++i)
{
cin>>x>>y;
ins(x,y);ins(y,x);
}
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(vis,0,sizeof(vis));
_cnt=0;
memset(_head,0,sizeof(_head));
tarjan(1,0);
memset(vis,0,sizeof(vis));
memset(f,0,sizeof(f));
dfs(1);
int pos=0,ans=0;
for(int i=1;i<=n;++i)
if(f[i]>ans)
{
ans=f[i];
pos=i;
}
if(pos==0)
cout<<tot<<endl;
else
{
memset(f,0,sizeof(f));
memset(vis,0,sizeof(vis));
dfs(pos);
for(int i=1;i<=n;++i)
if(f[i]>ans)
ans=f[i];
cout<<tot-ans<<endl;
}
}
return 0;
}