1. 程式人生 > >【題解】[牛客網NOIP賽前集訓營-提高組(第三場)]B.公平競賽 bfs

【題解】[牛客網NOIP賽前集訓營-提高組(第三場)]B.公平競賽 bfs

題目連結
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述


在這裡插入圖片描述

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
inline int read()
{
	int s=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9')f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
	if(f)s=-s;return s;
}
const int N=5e3+10;
const int M=1e6+10;
const int INF=0x3f3f3f3f;
int op,n,m,tot,hd[N<<1],vis[N<<1],len[N<<1],ans[N<<1],minn=INF,pre[N<<1];
struct Edge{
	int v,nx;
}e[M<<1];
inline void add(int u,int v)
{
	e[++tot].v=v;
	e[tot].nx=hd[u];
	hd[u]=tot;
}
inline void bfs(int s)
{
	memset(vis,0,sizeof(vis));memset(len,0,sizeof(len));memset(pre,0,sizeof(pre));
    queue<int>q;while(q.size())q.pop();q.push(s);vis[s]=1;
    while(q.size())
    {
    	int u=q.front();q.pop();
    	if(2*len[u]+1>=minn)return;
    	for(int i=hd[u];i;i=e[i].nx)
    	{
    		int v=e[i].v;
    		if(v==pre[u])continue;
    		if(!vis[v])
    		{
    			vis[v]=1;q.push(v);pre[v]=u;len[v]=len[u]+1;
			}
			else
			{
				if(len[u]+len[v]+1<minn)
				{
					minn=len[u]+len[v]+1;
					int tp=0;
					for(int j=u;j;j=pre[j])ans[++tp]=j;
					reverse(ans+1,ans+tp+1);
					for(int j=v;j;j=pre[j])ans[++tp]=j;
				}
				return;
			}
		}
	}
}
int main()
{
	//freopen("in.txt","r",stdin);
    op=read();
    while(1)
    {
    	n=read();if(!n)break;m=read();
    	memset(hd,0,sizeof(hd));tot=0;minn=INF;
    	for(int i=1,a,b;i<=m;i++)
    	    a=read(),b=read(),add(a,b+n),add(b+n,a);
    	for(int i=1;i<=n;i++)bfs(i);
    	if(minn==INF)puts("-1");
    	else
    	{
    		printf("%d\n",minn);
    		for(int i=1;i<=minn;i++)
    		    printf("%d ",ans[i]>n?ans[i]-n:ans[i]);
    		puts("");
		}
	}
	return 0;
} 

總結

拆點後在二分圖中bfs找最小環