CF453C Little Pony and Summer Sun Celebration

题意

给一个无向图,nn 个点 mm 条边,给定一个 0101 序列 a1ana_1…a_n,如果 ai=1a_i=1,要求走到这个点奇数次,否则,要求走到这个点偶数次,请你任选起点,输出满足要求的序列长度和经过点的序列,序列长度不能超过 4×n4\times n,若无解则输出 1-1

分析

  • 如果我们走过一个要走奇数次的点,那么它还要被走偶数次

  • 如果我们走过一个要走偶数次的点,那么它还要被走奇数次

换句话说:

  • 1    01\implies0

  • 0    10\implies1

这不就是逻辑非运算吗!

于是问题就变成了:

给一个无向图,nn 个点 mm 条边,给定一个 0101 序列 a1ana_1…a_n,每次经过第 ii 个点时 ai !aia_i\Rightarrow\ !a_i,要求把所有的 aia_i 变成 00。请你任选起点,输出满足要求的序列长度和经过点的序列,序列长度不能超过 4×n4\times n,若无解则输出 1-1

接下来我们任选一个点作为起点 rootroot,且满足 aroot=1a_{root}=1,从 rootroot 出发进行深搜,对于每个走到的点 xx,并执行 ax !axa_x\Rightarrow\ !a_x,表示走到一次,接下来走 xx 的未被访问的儿子 sonx,ison_{x,i},并回溯 ax !axa_x\Rightarrow\ !a_x,如果访问完后 axa_x 还是 11,就走回他的父节点 fafa 再走回来,就可以保证 ax=0a_x=0。每次走记得记录路径。

搜索结束后,判断是否有 aia_i11 而未被访问过的点,若有,则表明该图不连通且两边都有需要走奇数次的点,显然无解,输出 11

最后判断一下 aroota_{root} 是否为 11,若是,取消最后一次返回父节点的操作,即序列长度减去 11,就可以输出答案了。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,a[N],ans[4*N],s,root,v[N];
vector<int>e[N];
void dfs(int x,int fa)
{
	a[x]=!a[x];
	ans[++s]=x;
	v[x]=1;
	for(int i=0;i<e[x].size();i++)
		if(!v[e[x][i]])
		{
			dfs(e[x][i],x);
			a[x]=!a[x];
			ans[++s]=x;
		}
	if(fa>0&&a[x])
	{
		ans[++s]=fa,ans[++s]=x;
		a[fa]=!a[fa],a[x]=!a[x];
	}
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
    	int u,v;
    	cin>>u>>v;
    	e[u].push_back(v);
    	e[v].push_back(u);
	}
    for(int i=1;i<=n;i++)
    {
    	cin>>a[i];
    	if(a[i])
    		root=i;
	}
	if(root)
	{
		dfs(root,0);
		for(int i=1;i<=n;i++)
			if(a[i]&&!v[i])
			{
				cout<<-1;
				return 0;
			}
	}
	if(a[root])
		s--;
	cout<<s<<endl;
	for(int i=1;i<=s;i++)
		cout<<ans[i]<<" ";
	return 0;
}
posted @ 2021-08-05 18:16  luckydrawbox  阅读(7)  评论(0)    收藏  举报  来源