n个点m条无向边的一个图,让你加一条边,使得桥数最少,输出最少桥的个数。
先缩点,然后图中所有的点都成了“桥”,然后我们求出缩点的个数sig,此时有sig-1条桥,然后我们连一个边,使其成为最大环,当然就是连接直径的两端点啦!就是sig-1-zhijing。
//DFS版
#include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define INF 0x3f3f3f3f
using namespace std;
const int MAXN = 3e5+5;
const int MAXM = 7e5+5;
struct node
{
int from,to,next;
} e[150050*3];
struct ZhiJing
{
int head[150050];
int vis[150050];
int cont;
int mx,root;
void init()
{
cont=0;
memset(head,-1,sizeof(head));
}
void add(int from,int to)
{
e[cont].to=to;
e[cont].next=head[from];
head[from]=cont++;
}
void Dfs(int u,int from,int depth)
{
vis[u]=1;
if(depth>mx)
{
mx=depth;
root=u;
}
for(int i=head[u]; i!=-1; i=e[i].next)
{
int v=e[i].to;
if(vis[v]==0)
Dfs(v,u,depth+1);
}
}
void dfs(int u,int from,int depth)
{
vis[u]=1;
mx=max(mx,depth);
for(int i=head[u]; i!=-1; i=e[i].next)
{
int v=e[i].to;
if(vis[v]==0)
dfs(v,u,depth+1);
}
}
int solve()
{
mx=0;
root=1;
memset(vis,0,sizeof(vis));
Dfs(1,-1,0);
mx=0;
memset(vis,0,sizeof(vis));
dfs(root,-1,0);
return mx;
}
} zhi;
struct EDGE
{
int to,next,id;
} edges[MAXM*2];
stack<int> stk;
struct BianSuoDain
{
int n,m,sig,color[MAXN],heads[MAXN],edge_num,Inx,dfn[MAXN],low[MAXN],used[MAXM];
void init(int n1,int m1)
{
n=n1;
m=m1;
sig=0;
edge_num=0;
Inx=0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(used,0,sizeof(used));
memset(heads,255,sizeof(heads));
for(int i=0; i<=n; i++)
color[i]=0;
while(stk.size())
stk.pop();
//
}
void add_edge(int u,int v)
{
edges[edge_num].to = v;
edges[edge_num].next = heads[u];
heads[u] = edge_num++;
//printf("---");
}
void tarjan(int u,int fa)
{
dfn[u] = low[u] = ++Inx;
stk.push(u);
for(int i=heads[u]; i!=-1; i=edges[i].next)
{
// cout<<i<<endl;
int v = edges[i].to;
if(v==fa)
continue;
if(!dfn[v])
{
tarjan(v,u);
low[u] = min(low[u],low[v]);
}
else
low[u] = min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
//set<int> tmp_ver_set;//记录点的数量
//set<int> tmp_edge_set;//记录边的数量
//tmp_ver_set.insert(u);
int x;
sig++;
do
{
x = stk.top();
color[x]=sig;
//printf("%d--ddd-%d\n",x,color[x]);
stk.pop();
//tmp_edge_set.insert(edge[x].id);
//tmp_ver_set.insert(edge[x].to);
//在这里存储一个点双联通分量里的边、点
}
while(x!=u);
//if(tmp_edge_set.size()==tmp_ver_set.size())
// for(set<int>::iterator it=tmp_edge_set.begin(); it!=tmp_edge_set.end(); it++)
//ans.push_back(*it);//把边加进去
}
//cout<<"pp"<<endl;
}
void new_Map()
{
//cout<<"asdaq"<<endl;
zhi.init();
for(int i=1; i<=n; i++)
{
for(int j=heads[i]; j!=-1; j=edges[j].next)
{
//cout<<"|||"<<endl;
int v=edges[j].to;
if(color[i]!=color[v])
{
//printf("%d--%d\n",i,v);
//printf("%d--%d\n",color[i],color[v]);
//cout<<"asda"<<endl;
zhi.add(color[i],color[v]);
zhi.add(color[v],color[i]);
}
}
}
//cout<<"AsdfsasdSA"<<endl;
int ans1=sig-1-zhi.solve();
printf("%d\n",ans1);
}
void work()
{
for(int i=1; i<=n; i++)
{
if(!dfn[i])
{
//cout<<"++"<<endl;
tarjan(i,i);
}
}
//cout<<sig<<endl;
new_Map();
}
} bian;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d %d",&n,&m);
bian.init(n,m);
for(int i=1; i<=m; i++)
{
int u,v;
scanf("%d %d",&u,&v);
bian.add_edge(u,v);
bian.add_edge(v,u);
}
bian.work();
}
/*
3
3 3
1 2
2 3
3 1
7 7
1 2
2 3
3 1
3 4
4 5
4 6
6 7
*/
return 0;
}