【转载自我的洛谷博客】欧拉路、欧拉回路学习笔记

https://www.luogu.com.cn/blog/300078/ou-la-lu-ou-la-hui-lu-xue-xi-bi-ji

In Addition
【例】C. Johnny and Megan's Necklace

欧拉回路的建模是思维的一个难点。本题为典型的欧拉回路与二进制表示结合的题目。题解:考虑枚举 \(b\),那么就需要保证beauty都不低于 \(b\),即两个权值为 \(u,v\) 的节点可以相连等价于 \(u\&(2^b-1)=v\&(2^b-1)\)。图论建模,对每个部件\((p,q)\)在一张图上的 \(p\&(2^b-1),q\&(2^b-1)\) 两点间连双向边,在此得到了一张节点为 \(0\sim 2^b-1\)、共 \(n\) 条边的图,那么 \(b\) 是可以的当且仅当这是一张欧拉图。注意欧拉图可以有大小为1的连通块散落在旁。
评:可以积累套路

#include <bits/stdc++.h>
using namespace std;
const int N=2e6+5;
int n,tp,p,a[N],deg[N],ans[N],vis[N];
vector<pair<int,int> >G[N];
pair<int,int>stk[N];
void dfs(int s){
	stk[++tp]=make_pair(s,0);
	while(tp){
		int x=stk[tp].first,z=stk[tp].second;
		while(G[x].size()&&vis[abs(G[x].back().second)])G[x].pop_back();
		if(!G[x].size())ans[++p]=z,tp--;
		else {
			vis[abs(G[x].back().second)]=1;
			stk[++tp]=G[x].back();
		}
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=2*n;i++)cin>>a[i];
	for(int b=20;~b;b--){
		p=0,memset(vis,0,sizeof(vis)),memset(deg,0,sizeof(deg));
		for(int i=0;i<(1<<b);i++)G[i].clear();
		for(int i=2;i<=2*n;i+=2){
			int u=a[i]&((1<<b)-1),v=a[i-1]&((1<<b)-1);
			G[u].push_back(make_pair(v,i/2)),G[v].push_back(make_pair(u,-i/2));
			deg[u]++,deg[v]++;
		}
		bool flag=1;
		for(int i=0;i<(1<<b);i++)if(deg[i]&1){flag=0;break;}
		if(!flag)continue;
		for(int i=0;i<(1<<b)&&p<2;i++)p=0,dfs(i);
		if(p!=n+1)continue;
		cout<<b<<'\n';
		for(int i=p-1;i;i--)
			if(ans[i]>0)cout<<ans[i]*2<<' '<<ans[i]*2-1<<' ';
			else cout<<-1-ans[i]*2<<' '<<ans[i]*-2<<' ';
		break;
	}
}
posted @ 2022-01-12 14:05  pengyule  阅读(61)  评论(0)    收藏  举报