CF840B Leha and another game about graph

首先给出一个结论:给定一个连通图,要求构造一个给定每个点度数奇偶性的图(不要求连通,但新图的边集是原图边集的子集)。若奇点个数为奇数则无解;反之则一定有解。

无解非常好理解:因为图的所有点的总的度数一定为偶数,所以奇点个数显然不可能为奇数。

下面将通过构造的方式证明后者一定有解。

如何同时改变两个点的奇偶性:由于原图是连通的,我们只需要找到一条这两点之间的路径并翻转即可(翻转的意思是本来选改为不选,不选则改为选)。路径中其他点显然不改变奇偶性,而两端的奇偶性改变,这样我们就达到了目的。

我们假设一开始一条边都不选,那么没有奇点。由于要求奇点个数是偶数,所以我们可以把奇点随机两两配对,每次寻找一条路径操作来获得两个奇点(上面的方法),这样的构造一定可以满足要求。

下面给出一个具体的操作流程:

  1. 随便找一棵原图的生成树
  2. 以一个节点为根,计算每个子树内奇点个数
  3. \(x\) 子树内奇点个数为偶数,则不选 \(x\)\(fa_x\) 这条边,反之必须选

其中 \(fa_x\) 表示 \(x\) 的父亲节点。

关于3.的解释是,若子树内要求的奇点是奇数个,则显然无法通过子树内部的匹配来解决这些奇点,必然会有奇数个点要向子树外连边,所以 \(x \to fa_x\) 这条边一定被选择了奇数次,所以最后呈现出来的是必须要选。

对于这道题增加了度数可奇可偶的一种点。显然,如果有这种点那么一定有解,我们可以在保证奇点个数为偶数的前提下随便安排这些点。若没有这种点,则需要通过奇点个数来判断是否有解。剩下的就直接按照上面的方法做即可。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=300009;
int head[N],cnt,n,m,deg[N],flag,all,fa[N],x[N],y[N],ans[N],siz[N],Ans;
struct Edge
{
	int nxt,to,w;
}g[N*2];

void add(int from,int to,int w)
{
	g[++cnt].nxt=head[from];
	g[cnt].to=to;
	g[cnt].w=w;
	head[from]=cnt;
}

void init()
{
	scanf("%d %d",&n,&m);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&deg[i]);
		if(deg[i]==-1) flag=1;
		else all+=deg[i];
		fa[i]=i;
	}
	for (int i=1;i<=m;i++)
		scanf("%d %d",&x[i],&y[i]);
}

int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); }

void dfs(int x,int fa,int k)
{
	siz[x]=deg[x];
	for (int i=head[x];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(v==fa)
			continue;
		dfs(v,x,g[i].w);
		siz[x]+=siz[v];
	}
	if(siz[x]&1)
		ans[k]=1;
}

void work()
{
	if(!flag&&(all&1))
	{
		puts("-1");
		return;
	}
	for (int i=1;i<=n;i++)
		if(deg[i]==-1)
			if(all&1)
				all++,deg[i]=1;
			else
				deg[i]=0;
	for (int i=1;i<=m;i++)
	{
		int A=find(x[i]),B=find(y[i]);
		if(A!=B)
			fa[B]=A,add(x[i],y[i],i),add(y[i],x[i],i);
	}
	for (int i=head[1];i;i=g[i].nxt)
		dfs(g[i].to,1,g[i].w);
	for (int i=1;i<=m;i++)
		Ans+=ans[i];
	printf("%d\n",Ans);
	for (int i=1;i<=m;i++)
		if(ans[i])
			printf("%d\n",i);
}

int main()
{
	init();
	work();
	return 0;
}
posted @ 2020-06-27 13:30  With_penguin  阅读(130)  评论(0编辑  收藏  举报