CF453C Little Pony and Summer Sun Celebration(构造、贪心(?))

CF453C Little Pony and Summer Sun Celebration

题解

这道题要求输出任意解,并且路径长度不超过4n就行,所以给了我们乱搞构造的机会。

我这里给出一种构造思路:

首先一个连通块如果没有要求奇数次的点,那么就可以不管他,如果超过一个连通块内有要求奇数次的点,那么无解。

然后在那个唯一需要走的连通块里,我们随便抠一个生成树出来,从根遍历


首先把每次向下走以及回溯的路径记录到序列的新一位(并不需要一开始就把根节点加入,反正最后会回溯到根,于是最后一个元素添加为根),顺便记录奇偶性的变化,

这个过程增加的序列长度 <= 2n

然后在①的过程中,对于任意非根的点 i,当他要回溯到 fa[i] 时,如果他的次数奇偶性与我们想要的不同,那么在序列中加入一段“fa[i],i”,这样就把 i 和 i 的子树都能调对,回溯后再考虑fa[i],

这个过程增加的序列长度 <= 2n

在②的最后,回溯到根时,如果他的次数奇偶性不正确,就把序列最后一个元素(恰好就为根了吧)删掉,如果对于只有一个节点的情况,就在序列头加一个。

设个过程增加的序列长度在 -1 到 1 之间


可以证明,最终的序列长度不会超过4n。

C O D E

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<algorithm>
#define MAXN 100005
#define ENDL putchar('\n')
#define LL long long
#define lowbit(x) ((-x)&(x))
using namespace std;
inline LL read() {
	LL f = 1,x = 0;char s = getchar();
	while(s < '0' || s > '9') {if(s == '-')f = -1;s = getchar();}
	while(s >= '0' && s <= '9') {x = x * 10 + (s - '0');s = getchar();}
	return x * f;
}
int n,m,i,j,s,o,k,root;
vector<int> g[MAXN];
int fa[MAXN];
int findf(int x) {return fa[x] == x ? x:(fa[x] = findf(fa[x]));}
void unionSet(int x,int y) {fa[findf(x)] = findf(y);}
int c[MAXN],cnt;
bool f[MAXN];
int pr[MAXN*4],cnp;
int dfs(int x,int fa) {
	int res = c[x];
	f[x] = 1;
	for(int i = 0; i < g[x].size();i ++)  {
		if(g[x][i] != fa) {
			res = max(res,dfs(g[x][i],x));
		}
	}
	return res;
}
void dfs2(int x,int fa) {
	for(int i = 0; i < g[x].size();i ++)  {
		if(g[x][i] != fa) {
			pr[++ cnp] = g[x][i];
			c[g[x][i]] ^= 1;
			dfs2(g[x][i],x);
			pr[++ cnp] = x;
			c[x] ^= 1;
		}
	}
	if(fa) {
		if(c[x]) {
			pr[++ cnp] = fa;
			pr[++ cnp] = x;
			c[fa] ^= 1;
			c[x] ^= 1;
		}
	}
	else if(c[x]) {
		if(cnp > 0) cnp --;
		else pr[++ cnp] = x,c[x] ^= 1;
	}
	return ;
}
int main() {
	n = read();m = read();
	for(int i = 1;i <= n;i ++) fa[i] = i;
	for(int i = 1;i <= m;i ++) {
		s = read();o = read();
		if(findf(s) ^ findf(o))
			g[s].push_back(o),g[o].push_back(s),unionSet(s,o);
	}
	for(int i = 1;i <= n;i ++) c[i] = read();
	for(int i = 1;i <= n;i ++) {
		if(!f[i]) {
			int dt;
			cnt += (dt = dfs(i,0));
			if(dt) root = i;
		}
	}
	if(cnt > 1) {
		printf("-1\n");
		return 0;
	}
//	printf("cnt & root:%d %d\n",cnt,root);
	if(root) dfs2(root,0);
	printf("%d\n",cnp);
	for(int i = 1;i <= cnp;i ++) {
		printf("%d ",pr[i]);
	}ENDL;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值