CF453C Little Pony and Summer Sun Celebration
题目翻译:
给一个无向图,
n
n
n 个点
m
m
m 条边,给定一个
01
01
01 序列,如果
a
i
=
1
a_i=1
ai=1,要求走到这个点奇数次,否则,要求走到这个点偶数次,请你任选起点,输出满足要求的经过点的序列和序列长度,序列长度不能超过
4
×
n
4\times n
4×n。
前置芝士:0是偶数(或为此题最大难点
思路:
知道了前置芝士,就知道若图不连通且两个连通块内都有要求经过奇数次的点时无解,连通图一定有解。
我们发现,因为只关心经过点的次数的奇偶性,所以经过一次就相当于
a
i
⨁
1
a_i\bigoplus1
ai⨁1,最后要求把
a
a
a 全变成
0
0
0。
我们先建出一颗
d
f
s
dfs
dfs 生成树,然后遍历并记录答案。对于一个儿子节点,如果
a
s
o
n
x
!
=
0
a_{son_x}!=0
asonx!=0 那么就让
s
o
n
x
son_x
sonx 和
x
x
x 反复横跳直到
a
s
o
n
x
=
0
a_{son_x}=0
asonx=0。此时不用管父节点,因为在回溯的过程中父节点就更新好了。
最后特判一下虚拟节点
−
1
-1
−1 是否在答案序列中,在就把最后根反复横跳的操作去掉就好啦。
代码:
#include<bits/stdc++.h>
#define freo(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
#define ll long long
using namespace std;
const int maxn=1e5+5;
int n,m,head[maxn],ecnt,ans[maxn<<2],cnt,s,a[maxn],vis[maxn];
struct edge
{
int nxt,to;
}e[maxn<<1];
inline ll read()
{
ll ret=0;char ch=' ',c=getchar();
while(!(c<='9'&&c>='0')) ch=c,c=getchar();
while(c<='9'&&c>='0') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
return ch=='-'?-ret:ret;
}
void add(int x,int y)
{
e[++ecnt]=(edge){head[x],y};
head[x]=ecnt;
}
void dfs(int u,int _f)
{
ans[++cnt]=u;vis[u]=1;a[u]^=1;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(!vis[v]) dfs(v,u),a[u]^=1,ans[++cnt]=u;
}
if(a[u]) ans[++cnt]=_f,ans[++cnt]=u,a[_f]^=1,a[u]^=1;
}
int main()
{
//freo("a");
n=read(),m=read();
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
add(u,v);add(v,u);
}
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) if(a[i]) s=i;
if(s) dfs(s,-1);
for(int i=1;i<=n;i++) if(!vis[i]&&a[i]) {printf("-1");return 0;}
if(cnt>1&&ans[cnt-1]==-1) cnt-=3;
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++) printf("%d ",ans[i]);
return 0;
}