CF36E Two Paths (欧拉回路+构造)
题目大意:给你一张可能有重边的不保证联通的无向图,现在要在这个图上找出两条路径,恰好能覆盖所有边一次,根据边的编号输出方案,无解输出-1
一道很不错的欧拉路径变形题
首先要知道关于欧拉路径的一种算法:Hierholzer算法
欧拉路径与欧拉回路
我们称度为奇数的点为奇点,度为偶数的点为偶点
从一个点开始走,把其它所有边都走了一遍,叫欧拉路径
从一个点开始走,把其它所有边都走了一遍又回到了这个点,叫欧拉回路
如果图中存在欧拉回路,所有点均为偶点,画画图就明白了
如果图中不存在或仅存在两个奇点,那么这个图存在欧拉路径,且路径的起点终点一定分别是这两个奇点。把起点终点连起来不就变成欧拉回路了么
欧拉回路一定是欧拉路径
Hierholzer算法
从图中的一个奇点开始dfs,每遍历到一条边,就在图中删去这条边(包括反向边),然后递归指向的节点
直到当前节点相连的所有边都被删掉之后,把当前节点推入一个栈中,回溯
如果原图存在欧拉回路,就能搜出欧拉回路。如果存在欧拉路径,就会搜出欧拉路径。
栈中存储的是路径的倒序点序列,而边序列就是每次递归前删掉的边构成的序列
实现比较简单
那这道题该怎么搞呢?
(1)如果图中有>2个连通块,一定无解
(2)如果只有1个连通块,分为0个奇点,2个奇点,4个奇点讨论,其它情况都是无解
0个奇点就是欧拉回路,断开其中任意一条边,把路径拆成两条就是答案
2个奇点就是欧拉路径,断开其中任意一条边,把路径拆成两条就是答案
4个奇点的话,挑两个奇点连起来,再跑欧拉路径就行啦
(3)如果有2个连通块,说明这两条路径分别在这两个连通块里
对于每个连通块而言,只能存在0个奇点和2个奇点两种情况,讨论一下就好啦
代码写得好丑啊TvT
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define N1 20010
using namespace std; template <typename _T> void read(_T &ret)
{
ret=; _T fh=; char c=getchar();
while(c<''||c>''){ if(c=='-') fh=-; c=getchar(); }
while(c>=''&&c<=''){ ret=ret*+c-''; c=getchar(); }
ret=ret*fh;
} struct Edge{
int to[N1*],nxt[N1*],del[N1*],head[N1],cte;
void ae(int u,int v)
{ cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; }
}e; int n,m,num;
int inc[N1],vis[N1],use[N1],stk[N1],tp;
void dfs1(int x,int id)
{
int j,v; vis[x]=id; num++;
for(j=e.head[x];j;j=e.nxt[j])
{
v=e.to[j];
if(!vis[v]) dfs1(v,id);
}
}
void euler(int x)
{
int j,v,la=;
for(j=e.head[x];j;j=e.nxt[j])
{
if(e.del[j]) continue;
v=e.to[j]; e.del[j]=; e.del[j^]=;
euler(v); stk[++tp]=j>>;
}
}
void fkdown(){ puts("-1"); exit(); }
int odd[N1],cnt_odd; void solve0(int id,int esum)
{
int i;
for(i=;i<=n;i++) if(vis[i]==id)
{
euler(i);
if(tp<esum) fkdown();
printf("%d\n",tp);
while(tp) printf("%d ",stk[tp--]);
puts("");
break;
}
}
void solve2(int id,int esum)
{
euler(odd[]);
if(tp<esum) fkdown(); //
printf("%d\n",tp);
while(tp) printf("%d ",stk[tp--]);
puts("");
} int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d",&m);
int i,j,x,y,cnt_compo=; n=; e.cte=;
if(m==) fkdown();
for(i=;i<=m;i++)
{
read(x), read(y), e.ae(x,y), e.ae(y,x);
inc[x]++, inc[y]++, use[x]=, use[y]=;
}
for(i=;i<=n;i++) if(use[i] && !vis[i]) cnt_compo++, dfs1(i,cnt_compo);
if(cnt_compo>) fkdown();
if(cnt_compo==){
for(i=;i<=n;i++) if(inc[i]&) odd[++cnt_odd]=i;
if(!cnt_odd){ for(i=;i<=n;i++) if(inc[i])
{
euler(i);
if(tp<m) fkdown();
printf("%d\n",tp-);
while(tp>) printf("%d ",stk[tp--]);
puts("");
puts("");
while(tp>) printf("%d ",stk[tp--]);
puts("");
break;
} }else if(cnt_odd==){ euler(odd[]);
if(tp<m) fkdown();
printf("%d\n",tp-);
while(tp>) printf("%d ",stk[tp--]);
puts("");
puts("");
while(tp>) printf("%d ",stk[tp--]);
puts(""); }else if(cnt_odd==){ e.ae(odd[],odd[]); e.ae(odd[],odd[]);
euler(odd[]);
if(tp-<m) fkdown();
while(tp)
{
if(stk[tp]>m) break;
tp--;
}
printf("%d\n",m+-tp);
for(i=m+;i>tp;i--) printf("%d ",stk[i]);
puts("");
tp--; printf("%d\n",tp);
while(tp) printf("%d ",stk[tp--]);
puts(""); }else fkdown();
}else{
int esum=; cnt_odd=; esum=;
for(i=;i<=n;i++)
{
if(!vis[i] || vis[i]==) continue;
if((inc[i]&)) odd[++cnt_odd]=i;
esum+=inc[i];
}
if(cnt_odd> || cnt_odd&) fkdown(); cnt_odd=; esum=;
for(i=;i<=n;i++)
{
if(!vis[i] || vis[i]==) continue;
if((inc[i]&)) odd[++cnt_odd]=i;
esum+=inc[i];
}
if(cnt_odd> || cnt_odd&) fkdown();
esum>>=;
if(!cnt_odd) solve0(,esum);
else if(cnt_odd==) solve2(,esum);
else fkdown(); cnt_odd=; esum=;
for(i=;i<=n;i++)
{
if(!vis[i] || vis[i]==) continue;
if((inc[i]&)) odd[++cnt_odd]=i;
esum+=inc[i];
}
esum>>=;
if(!cnt_odd) solve0(,esum);
else if(cnt_odd==) solve2(,esum);
else fkdown();
}
return ;
}
CF36E Two Paths (欧拉回路+构造)的更多相关文章
- D. Bear and Two Paths(贪心构造)
D. Bear and Two Paths time limit per test 2 seconds memory limit per test 256 megabytes input standa ...
- hdu 4850 字符串构造---欧拉回路构造序列 递归+非递归实现
http://acm.hdu.edu.cn/showproblem.php? pid=4850 题意:构造长度为n的字符序列.使得>=4的子串仅仅出现一次 事实上最长仅仅能构造出来26^4+4- ...
- BZOJ3724PA2014Final Krolestwo——欧拉回路+构造
题目描述 你有一个无向连通图,边的总数为偶数.设图中有k个奇点(度数为奇数的点),你需要把它们配成k/2个点对(显然k被2整除).对于每个点对(u,v),你需要用一条长度为偶数(假设每条边长度为1)的 ...
- BZOJ3724 PA2014Final Krolestwo(欧拉回路+构造)
如果没有长度为偶数的限制,新建一个点向所有奇点连边,跑欧拉回路即可,显然此时一定存在欧拉回路,因为所有点度数都为偶数. 考虑长度为偶数的限制,将每个点拆成两个点放进一个二分图里,那么每条原图中的边在二 ...
- CF1005F Berland and the Shortest Paths (树上构造最短路树)
题目大意:给你一个边权为$1$的无向图,构造出所有$1$为根的最短路树并输出 性质:单源最短路树上每个点到根的路径 ,一定是这个点到根的最短路之一 边权为$1$,$bfs$出单源最短路,然后构建最短路 ...
- 转--python 黑魔法2
Python 高效编程小技巧 个人博客:临风|刀背藏身 Python 一直被我拿来写算法题,小程序,因为他使用起来太方便了,各种niubi闪闪的技能点也在写算法的过程中逐渐被挖掘到,感谢万能的谷哥度娘 ...
- NOI前训练日记
向别人学习一波,记点流水帐.17.5.29开坑. 5.29 早晨看了道据说是树状数组优化DP的题(hdu5542),然后脑补了一个复杂度500^3的meet in the middle.然后死T... ...
- IOI 2020 集训队作业胡扯
首先安慰自己:做的没集训队快很正常-- 很正常-- 做不完也很正常-- 很正常-- 全都不会做也很正常-- 很正常-- 表格 试题一 完成情况 试题二 完成情况 试题三 完成情况 cf549E cf6 ...
- 使用Java8 Files类读写文件
Java8 Files类的newBufferedReader()和newBufferedWriter()方法 这两个方法接受Path类型的参数.Path 类是Java8 NIO中的接口.可以由Path ...
随机推荐
- Android 应用按返回键异常退出的问题
开发过程中遇到按返回键异常退出的问题,log显示为空指针异常,进一步产看是由于onActivityResult得到的Intent为空. 按返回键复写代码例如以下: @Override public v ...
- [转] CV Datasets on the web
转自:CVPapers This material is presented to ensure timely dissemination of scholarly and technical wor ...
- DIV+CSS在不同浏览器中的表现
在给员工培训DIV+CSS的过程中.他们向我提出了非常多问题,有些问题我自己也没有想到过于是抽了些时间自己进行了一番实验,所有实验在IE7和Firefox中进行: 实验一.假设一个div没有指定 ...
- 微信小程序图片选择,预览和删除
这里均用的是小程序原生api 废话不多说直接上栗子: <view class="addImv"> <!--这个是已经选好的图片--> <view wx ...
- JavaScript中的substr和Java中的substring
JavaScript::substr(index, length)从下标开始截取多少位,如果length为空,则截取到最后,-1倒数第一位,-2倒数第二位.... Java:substring(sta ...
- Java初学者如何排查学习中遇到的问题
大多数新手或者刚入门的人在学习的时候,不管是看视频还是看书,都会遇到各种各样的问题,比如JDK配置了,但是javac没有办法执行,Eclipse安装了,但是打不开,快捷键用不了,照着视频敲了但是和视频 ...
- SpringBoot2.0整合SpringSecurity实现WEB JWT认证
相信很多做技术的朋友都做过前后端分离项目,项目分离后认证就靠JWT,费话不多说,直接上干活(写的不好还请多多见谅,大牛请绕行) 直接上代码,项目为Maven项目,结构如图: 包分类如下: com.ap ...
- Java学习-异常2
1.异常处理的第一种方式是:上抛[throws] 2.异常处理的第二种方式是:try....catch..如果不想让调用程序知道该异常发生了,被调用的程序应该使用try...catch..进行异常捕捉 ...
- Linux命令(004) -- watch
对Linux系统的操作过程中,经常会遇到重复执行同一命令,以观察其结果变化的情况.惯用的方法是:上下键加回车,或是Ctr+p然后回车.今天我们来了解一下watch命令,它可以帮助我们周期性的执行一个命 ...
- jsp: ServletContext
WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用. ServletConfig对象中维护了ServletContext对象的引用,开发 ...