当前位置: 首页 > article >正文

CF1494F Delete The Edges 题解

Description

给定一张 n n n 个点、 m m m 条边的图,你可以从图上任意一点出发,目标是删去所有的边,当一条边被删去后你不能再走此边。

初始模式下,一条边在你走过后会立即被删去。

你可以在任意一点切换模式(或全程不换),换完模式后走过的第偶数条便会被删去,且不可重新换回初始模式。

求一组方案。

Solution

观察样例可得切换模式后走的图为一个菊花图,下面浅浅分析一下。

假设只有一条边,则折返走一遍便能删完。

若为两条边 ( i , j ) , ( j , k ) (i,j),(j,k) (i,j),(j,k),发现只能 j → i → j → k → j j\rightarrow i\rightarrow j\rightarrow k\rightarrow j jijkj 将其删完。

依此类推,删边必须像 i → j → i i\rightarrow j\rightarrow i iji 折返地删。

所以我们可以枚举菊花图的中心,构造出走一条终点为菊花图中心的欧拉路径,然后切换模式的方案。

关键在于如何求出这条欧拉路径。

首先将所有和中心相连的奇点(度数为奇)和中心连的这条边删去,这样这个点就会变为偶点(度数为偶),方便后续操作。

然后得出当前图中奇点个数 c n t cnt cnt,和中心度数是否为 0 0 0,记为 f f f

f = t r u e f=true f=true

  • c n t > 2 cnt>2 cnt>2,无法构出欧拉路径,非法。

  • c n t = 2 cnt=2 cnt=2 且中心不为奇点,终点不为中心,非法。

  • c n t = 2 cnt=2 cnt=2 且外围图不连通(除去度数为 0 0 0 的点,这些点虽然不连通,但切换模式后都会连通),非法。

  • c n t = 2 cnt=2 cnt=2 且外围连通,即我们已经构造出了合法方案。

f = f a l s e f=false f=false

  • c n t ≥ 2 cnt\ge2 cnt2,还要连一条边到中心,然而再加边就不是欧拉路径了,非法。

剩下还剩当前路径有中心但外围不连通、当前路径不含中心两种情况,发现 c n t = 0 cnt=0 cnt=0 使得我们可以在加一条删去的边到欧拉路径上,那我们就枚举这条边。

首先当前外围图(此时是除去度数为 0 0 0 的点但此点不为中心)连通块个数要小于等于 2 2 2,因为加一条边只能让两个连通块连通。

然后分别将这两连通块染色,遍历删去的边,若边的两顶点颜色不同,则加上这条边,发现这种合法方案的起点就是这两顶点中不是中心的那个点。

发现一定存在这条先前被删去的边,即我们一定能找到合法方案。

然后我们按输出要求输出方案即可,首先遍历欧拉路径,再切换模式,然后折返删菊花图。

代码细节很多,理清思路再写。

时间复杂度 O ( n ( n + m ) ) O(n(n+m)) O(n(n+m))

Code

#include<bits/stdc++.h>
using namespace std;
int n,m;
int tot,head[3030];
int in[3030],du[3030],col[3030];
bool vis[3030],viss[3030],pit[3030];
vector<int> path;
struct edge{
	int to,next,id;
}e[6060];
void add(int x,int y,int z){
	e[++tot]=edge{y,head[x],z};
	head[x]=tot;
}
void dfs(int x,int v=0){
	viss[x]=1;
	col[x]=v;
	for(int i=head[x];i;i=e[i].next){
		int y=e[i].to,w=e[i].id;
		if(viss[y]||vis[w]) continue;
		dfs(y,v);
	}
}
void get(int x){
	bool f=0;
	int ss,ww;
	for(int i=head[x];i;i=e[i].next){
		int y=e[i].to,w=e[i].id;
		if(!vis[w]){
			vis[w]=1;
			get(y);
			path.push_back(x);
		}
	}
}
bool solve(int st){
	for(int i=1;i<=n;i++) du[i]=in[i],viss[i]=0,pit[i]=0,col[i]=0;
	for(int i=1;i<=m;i++) vis[i]=0;
	bool f=0;
	int ts=0,ttot=0;  //ts为方案起点、ttot为切换模式后删的边数
	for(int i=head[st];i;i=e[i].next){
		int y=e[i].to,w=e[i].id;
		if(du[y]%2){  //删去中心与偶点相连的边
			pit[y]=1,du[y]--,du[st]--,vis[w]=1,ttot++;
		}else f=1;  //中心是否在当前欧拉路径上
	}
	int cnt=0,fl=0;
	for(int i=1;i<=n;i++){
		if(du[i]%2) cnt++;  //奇点数量
		if(du[i]%2&&i!=st) fl=i;  //得出合法欧拉路径的起点
	}
	if(f){
		if(fl==0) fl=st;  //欧拉回路则任选起点
		if(cnt>2) return 0;
		if(cnt==2&&du[st]%2==0) return 0;
		if(cnt==2){
			dfs(st);
			for(int i=1;i<=n;i++){  //判断外围连通性
				if(du[i]==0) continue;
				if(!viss[i]) return 0;
			}
			ts=fl;
		}
		
	}else{
		if(cnt>=2) return 0;
	}
	if(cnt==0){
		dfs(st);  //染第一个连通块
		bool ff=0;
		for(int i=1;i<=n;i++){
			if(du[i]==0) continue;
			if(!viss[i]){
				if(ff) return 0;  //有至少三个连通块
				dfs(i,1);
				ff=1;
			}
		}
		if(ff){
			for(int i=head[st];i;i=e[i].next){
				int y=e[i].to,w=e[i].id;
				if(pit[y]&&col[y]){  //是之前删去的奇点且与中心不在同一连通块上
					pit[y]=0,vis[w]=0,ttot--;
					ts=y,du[y]++,du[st]++;
					break;
				}
			}
		}else{  //只有一个连通块即为欧拉回路
			ts=st;
		}
	}
	cout<<m+ttot+2<<'\n';  //m条边要删完则有m次操作,ttot条边被操作2次,加上起点和切换模式的2次操作
	get(ts);  //遍历欧拉路径
	for(int i=path.size()-1;i>=0;i--) cout<<path[i]<<" ";
	cout<<st<<" ";
	cout<<-1<<" ";
	for(int i=head[st];i;i=e[i].next){
		int y=e[i].to,w=e[i].id;
		if(pit[y]){
			cout<<y<<" "<<st<<" ";  //折返删菊花图
		}
	}
	return 1;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(nullptr);
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		in[x]++,in[y]++;
		add(x,y,i),add(y,x,i);
	}
	for(int i=1;i<=n;i++){
		if(solve(i)){
			return 0;
		}
	}
	cout<<"0"<<'\n';  //无解
	return 0;
}

http://www.kler.cn/news/316745.html

相关文章:

  • Java代码调用https(SSL证书验证问题)
  • 828华为云征文 | 将Vue项目部署到Flexus云服务器X实例并实现公网访问
  • 使用Conda配置python环境到Pycharm------Window小白版
  • SVN泄露 CTFHUB 解题笔记
  • 论文不会写快来看!分享4款ai改写论文软件
  • uni-app快速入门
  • 异常值理解
  • 尚品汇-秒杀商品定时任务存入缓存、Redis发布订阅实现状态位(五十一)
  • 修复 blender 中文输入 BUG (linux/wayland/GNOME/ibus)
  • 如何降低H5商城系统的开发成本
  • unixODBC编程(一)安装配置ODBC
  • 【STL】vector 基础,应用与操作
  • Java综合练习题—TCP通信协议+xml操作+序列化反序列化综合题
  • 如何使用ant design vue的a-select下拉框,实现既能输入内容,也可以下拉选择的效果,apiselect同样适用
  • 浅谈spring 后端项目配置logback日志
  • 无人机之4G模块的主要功能和优势
  • 华为HarmonyOS地图服务 1 -- 如何实现地图呈现?
  • Flask高级特性实战
  • 字符串反转
  • 【kafka-04】kafka线上问题以及高效原理
  • HarmonyOS鸿蒙开发实战(5.0)网格元素拖动交换案例实践
  • Go语言并发编程之sync包详解
  • 前后端分离,使用MOCK进行数据模拟开发,让前端攻城师独立于后端进行开发
  • 【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL21
  • Kotlin高阶函数func
  • 计算机毕业设计 美妆神域网站的设计与实现 Java实战项目 附源码+文档+视频讲解
  • 一对一视频通话软件Call-Me
  • 某采招网爬虫数据采集逆向
  • 医学数据分析实训 项目四 回归分析--预测帕金森病病情的严重程度
  • I.MX6U裸机-C语言版LED灯实验