CF453C Little Pony and Summer Sun Celebration

本文介绍了解决一个关于图论和序列操作的问题,给定一个无向图和节点要求奇偶次经过的规则,通过深度优先搜索构建生成树并调整路径,确保满足所有点的奇偶要求。关键在于理解奇偶次经过的转换规则并利用DFS策略求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 ai1,最后要求把 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值