• CF840B Leha and another game about graph


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

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

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

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

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

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

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

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

    关于3.的解释是,若子树内要求的奇点是奇数个,则显然无法通过子树内部的匹配来解决这些奇点,必然会有奇数个点要向子树外连边,所以 (x o 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
    ",Ans);
    	for (int i=1;i<=m;i++)
    		if(ans[i])
    			printf("%d
    ",i);
    }
    
    int main()
    {
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    R set.seed()
    R tapply()
    R table
    清除R console中出现加号+
    r向量映射
    Java常识1
    IDEA配置
    SQL.字符串重叠项数量统计
    SQL.数据库内拆分字符串并返回数据表
    IDEA--TomCat配置
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13198135.html
Copyright © 2020-2023  润新知