Codechef:Selling Tickets/TICKETS(BFS搜尋樹)
阿新 • • 發佈:2018-11-01
題解:
這道題有點妙啊。
首先非法肯定是存在一個生成圖使得邊數大於點數。
然後就變成了找某個 到 的最短的三條路徑或者環連線環的情況。利用BFS搜尋樹的性質可以巧妙解決。
對於第一種,直接列舉 ,然後從 開始BFS,不讓 入隊,取離 最近的三個點,顯然無論重不重合,算出來的大等於答案。 而且我們又可以保證答案一定能取到。
對於第二種,列舉一個根來做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();
}