Codechef:Selling Tickets/TICKETS(BFS搜索树)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/83106791

传送门

题解:
这道题有点妙啊。

首先非法肯定是存在一个生成图使得边数大于点数。

然后就变成了找某个 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();
}

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/83106791
今日推荐