1. 程式人生 > >Codechef:Selling Tickets/TICKETS(BFS搜尋樹)

Codechef:Selling Tickets/TICKETS(BFS搜尋樹)

傳送門

題解:
這道題有點妙啊。

首先非法肯定是存在一個生成圖使得邊數大於點數。

然後就變成了找某個 s s t t 的最短的三條路徑或者環連線環的情況。利用BFS搜尋樹的性質可以巧妙解決。

對於第一種,直接列舉 s

, t s,t ,然後從 s s 開始BFS,不讓 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(); }