acm-(欧拉路径、构造)Educational Codeforces Round 105 (Rated for Div. 2) F. Delete The Edges

题面
传送门
经过一番思索可发现如果要存在一种合法方案,图必须可以被划分成两个部分: G 1 G_1 G1 G 2 G_2 G2。其中 G 1 G_1 G1要求具有一条欧拉路径或欧拉回路,并且在欧拉路径(回路)的终点 t t t处有一个以 t t t为中心的菊花图 G 2 G_2 G2 G 1 G_1 G1 G 2 G_2 G2共同构成 G G G

关键是如何找到 G 1 G_1 G1 G 2 G_2 G2。考虑枚举 t t t,对于每个 t t t我们先考虑那些非临接点中有几个点的度数是奇数:
若有两个及以上,那么显然 t t t是不能作为 G 2 G_2 G2的菊花图中心点;
若有一个,那么显然 G 1 G_1 G1的欧拉路径必须以那唯一一个奇度数的非临接点 s s s为起点, t t t为终点,自然所有奇度数的临接点与 t t t相连的边都得放到 G 2 G_2 G2,我们先将这些边删除,然后跑一遍欧拉路径,最后统计看 G 1 + G 2 G_1+G_2 G1+G2是否等于 G G G即可;
若有零个,那么欧拉路径的起点只能在 t t t的临接点找,并且还必须得是奇度数,不妨枚举这些奇度数的临接点 s s s,除了 s s s以外的奇度数的点与 t t t相连的边都得划分到 G 2 G_2 G2中,还是像上一种情况一样 c h e c k check check一下看是否 G 1 G_1 G1连通,然后 G 1 + G 2 G_1+G_2 G1+G2是否等于 G G G。如果没有奇度数的临接点的话,那么整个图显然存在一个从 t t t t t t的欧拉路径。

虽然讲起来简单,但是代码还是不太好写,具体细节见代码。

#include <bits/stdc++.h>
using namespace std;


const int maxn = 6005;

int h[maxn],ee=0,vs[maxn],n,m,deg[maxn],near[maxn];
struct EDGE{
	int u,v;
}edge[maxn];
struct Edge{
	int v,next;
}e[maxn];
void init(int n){
	memset(h,-1,sizeof(int)*(n+2));
	memset(deg,0,sizeof(int)*(n+2));
	ee=0;
}
void addedge(EDGE &edge){
	int u=edge.u,v=edge.v;
	deg[u]++;
	deg[v]++;
	e[ee]=Edge{v,h[u]};
	h[u]=ee++;
	e[ee]=Edge{u,h[v]};
	h[v]=ee++;
}
vector<int>ans1;
vector<int>ans2;
void dfs(int u){
	while(~h[u]){
		int i=h[u];
		int v=e[i].v;
		h[u]=e[h[u]].next;
		if(vs[i])continue;
		vs[i]=vs[i^1]=1;
		deg[u]--,deg[v]--;
		dfs(v);
		ans1.push_back(v);
	}
}
bool work(int u){
	memset(near,0,sizeof(int)*(n+2));
	memset(vs,0,sizeof(int)*(2*m+4));
	for(int i=h[u];~i;i=e[i].next){
		int v=e[i].v;
		near[v]=1;
	}
	int ct=0,s=0;
	for(int i=1;i<=n;++i){
		if(!near[i] && i!=u){
			if(deg[i]&1){
				ct++;
				s=i;
			}
		}
	}
	if(ct>=2)return false;
	if(ct==1){
		for(int i=h[u];~i;i=e[i].next){
			int v=e[i].v;
			if(deg[v]&1){
				vs[i]=vs[i^1]=1;
				deg[v]--,deg[u]--;
				ans2.push_back(v);
				ans2.push_back(u);
			}
		}
		dfs(s);
		ans1.push_back(s);
		reverse(ans1.begin(),ans1.end());
		for(int i=1;i<=n;++i)if(deg[i])return false;
		return true;
	}else{
		s=0;
		vector<EDGE>g;
		for(int i=h[u];~i;i=e[i].next){
			int v=e[i].v;
			if(deg[v]&1)g.push_back(EDGE{i,e[i].v}),vs[i]=vs[i^1]=1,deg[u]--,deg[v]--;
		}
		for(auto d:g){
			s=d.v;int i=d.u;
			vs[i]=vs[i^1]=0;
			deg[u]++,deg[s]++;
			ans1.clear();
			dfs(s);
			ans1.push_back(s);
			bool ok=true;
			for(int i=1;i<=n;++i)if(deg[i]){
				ok=false;
				break;
			}
			if(ok){
				reverse(ans1.begin(),ans1.end());
				for(auto dd:g){
					if(dd.v!=s){
						ans2.push_back(dd.v);
						ans2.push_back(u); 
					}
				}
				return true;
			}
			memset(vs,0,sizeof(int)*(2*m+4)); 
			init(n);
			for(int i=1;i<=m;++i)addedge(edge[i]);
			for(auto dd:g)vs[dd.u]=vs[dd.u^1]=1,deg[u]--,deg[dd.v]--;
		}
		for(int i=h[u];~i;i=e[i].next){
			int v=e[i].v;
			if(deg[v]&1){
				ans2.push_back(v);
				ans2.push_back(u);
			}
		}
		if(!(deg[u]&1))dfs(u);else return false;
		ans1.push_back(u);
		for(int i=1;i<=n;++i)if(deg[i])return false;
		return true;
	}
	return false;
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i)scanf("%d%d",&edge[i].u,&edge[i].v);
	for(int i=1;i<=n;++i){
		init(n);
		for(int j=1;j<=m;++j)addedge(edge[j]);
		if(work(i)){
			if(ans2.empty())printf("%d\n",(int)ans1.size());
			else printf("%d\n",(int)ans1.size()+1+(int)ans2.size());
			for(auto u:ans1){
				printf("%d ",u);
			}
			if(!ans2.empty())printf("-1 ");
			for(auto u:ans2)printf("%d ",u);puts("");
			return 0;
		}
	}
	printf("0\n");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值