题解:
这道题有点妙啊。
首先非法肯定是存在一个生成图使得边数大于点数。
然后就变成了找某个 s s s到 t t t的最短的三条路径或者环连接环的情况。利用BFS搜索树的性质可以巧妙解决。
对于第一种,直接枚举 s , t s,t s,t,然后从 s s s开始BFS,不让 t t t入队,取离 t t t最近的三个点,显然无论重不重合,算出来的大等于答案。 而且我们又可以保证答案一定能取到。
对于第二种,枚举一个根来做BFS搜索树,然后一个环肯定是一个横跨边。强制两个环lca为根,然后取两个最小值更新答案即可。正确性同上。
#include <bits/stdc++.h>
using namespace std;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=1e3+50, inf=1e8;
int n,m,ans,g[N],nt[N],vt[N],ec=1;
int dep[N],fa[N];
inline void add(int x,int y) {nt[++ec]=g[x]; g[x]=ec; vt[ec]=y;}
inline int lca(int x,int y) {
while(x^y) (dep[x]<dep[y]) ? y=fa[y] : (x=fa[x]);
return x;
}
inline void calc1(int s,int t) {
static int q[N],r; q[r=1]=s;
for(int i=1;i<=n;i++) dep[i]=-1; dep[s]=0;
for(int i=1;i<=r;i++) {
int u=q[i];
for(int e=g[u];e;e=nt[e])
if(vt[e]^t && !~dep[vt[e]])
dep[vt[e]]=dep[u]+1, q[++r]=vt[e];
}
int mn=inf, _mn=inf, __mn=inf;
for(int e=g[t];e;e=nt[e]) if(~dep[vt[e]]) {
int v=dep[vt[e]];
if(v<mn) __mn=_mn, _mn=mn ,mn=v;
else if(v<_mn) __mn=_mn, _mn=v;
else if(v<__mn) __mn=v;
} ans=min(ans,__mn+_mn+mn+2);
}
inline void calc2(int s) {
static int q[N],r,tre[N]; fa[q[r=1]=s]=0;
for(int i=1;i<=n;i++) dep[i]=-1; dep[s]=0;
for(int i=2;i<=ec;i++) tre[i]=0;
for(int i=1;i<=r;i++) {
int u=q[i];
for(int e=g[u];e;e=nt[e])
if(!~dep[vt[e]]) tre[e]=tre[e^1]=1, dep[vt[e]]=dep[u]+1, fa[vt[e]]=u, q[++r]=vt[e];
}
int mn=inf, _mn=inf;
for(int i=1;i<=n;i++) if(~dep[i])
for(int e=g[i];e;e=nt[e]) if(!tre[e] && ~dep[vt[e]]) {
tre[e]=tre[e^1]=1;
int v=dep[i]+dep[vt[e]]-dep[lca(i,vt[e])];
if(mn>v) _mn=mn, mn=v;
else if(_mn>v) _mn=v;
}
ans=min(ans,_mn+mn+1);
}
inline void solve() {
memset(g,0,sizeof(g)); ec=1;
n=rd(), m=rd(), ans=min(n,m);
for(int i=1;i<=m;i++) {
int x=rd(), y=rd();
add(x,y), add(y,x);
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++) calc1(i,j);
for(int i=1;i<=n;i++) calc2(i);
cout<<ans<<'\n';
}
int main() {
for(int i=rd();i;i--) solve();
}