zoukankan      html  css  js  c++  java
  • 【刷题】BZOJ 3724 PA2014Final Krolestwo

    Description

    你有一个无向连通图,边的总数为偶数。

    设图中有k个奇点(度数为奇数的点),你需要把它们配成k/2个点对(显然k被2整除)。对于每个点对(u,v),你需要用一条长度为偶数(假设每条边长度为1)的路径将u和v连接。每条路径允许经过重复的点,但不允许经过重复的边。这k/2条路径之间也不能有重复的边。

    Input

    第一行有两个整数n,m(2<=n,m<=250000),分别表示点数、边数,m为偶数。

    接下来m行,每行两个整数a,b(1<=a,b<=n,a≠b),表示a,b间连有一条边。不存在重边。保证奇点的数目不为零。

    Output

    如果你认为无解就输出NIE。

    设图中有k个奇点,则输出由k/2部分组成,每个部分包含两行:第一行为u,v,l,表示连接的两个点,及路径长度。第二行为空格隔开的l个整数,表示u到v的路径。边按照输入顺序从1到m编号。

    若有多组答案,任意输出其中一个。

    Sample Input

    6 8

    1 2

    2 3

    3 4

    4 5

    5 6

    6 1

    1 4

    2 5

    Sample Output

    样例输出:

    1 5 2

    6 5

    2 4 2

    8 4

    另一种合法输出:

    1 5 6

    1 2 3 7 6 5

    2 4 2

    8 4

    Solution

    这题是个好题兼难题

    考虑假如没有路径长度为偶数的限制,那么就是把奇度数点两两配对连边,使得所有的点的度数均为偶数,然后跑欧拉回路;或者建一个新点,从它向所有奇点连边,起到同样的效果

    然而现在有了长度为偶数的限制,就不能简单这样连边了

    把每个点 (u) 拆点 (u_{left})(u_{right}) ,建成二分图,建一个新点向所有奇点的 (u_{left}) 连边

    考虑这个二分图的作用,我们如果能把原图中的边转换成二分图中的边,然后有一条 (u_{left})(v_{left}) 的路径,那么这条路径一定是偶数长度的(二分图的特性)

    所以我们想要达到这样一种状态,这个二分图里有原图中的边,然后特殊点(即新建的那个点)与所有原图中奇度数点有边相连,同时二分图中每个点的度数都是偶数。如果达到了这样一个状态,那么只要从特殊点开始跑一条欧拉回路,答案就出来了

    怎样达到这样的状态是个棘手的问题。首先看二分图有什么性质。如果 (u_{left}) 在二分图里的度数为偶数,那么 (u_{right}) 的度数也一定为偶数。因为在原图中所有点都是偶数度数(加了特殊点的边之后),而 (d[u_{left}]+d[u_{right}]=u) 在原图中的度数,如果保证了 (u_{left}) 的度数为偶数,那么 (u_{right}) 的度数必定也是偶数

    所以我们只要维持二分图左边的所有点的度数为偶数就好了

    考虑拉出原图的一棵生成树,剩下的边在二分图中随意连,因为无论连出来的度数怎样,生成树都可以进行调整

    剩下的边任意连完后,从叶子到根遍历生成树。当前到了 (x) 点,如果 (x_{left}) 的度数现在是奇数,那么 (x)(fa[x]) 的这条边在二分图中就连 (x_{left})(fa[x]_{right}) ,这样做就可以把 (x_{left}) 的度数从奇数调成偶数;反之同理

    由于是从叶子到根遍历的,我们把一个点的度数调整好为奇数后就不会再被改变了

    那么二分图要达到的状态便完成了

    跑完欧拉回路考虑怎么找答案

    我们建了一个特殊点,这些特殊点向所有原图中的奇度数点的 (left) 点都连了边,所以跑欧拉回路,要求所有边都遍历到,那么每次从特殊点出去一次,必定也会回来一次,而出去所到的点与回来出发的点都是 (left) 点,正好满足路径长度为偶数的性质,于是,只要在欧拉路径中找不包含特殊点的极长段,这一段两端的点就是题目要求的一条路径的两个点,这一段中间的点就是要经过的点,稍加处理就好了

    #include<bits/stdc++.h>
    #define ui unsigned int
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    const int MAXN=500000+10;
    int n,m,e=1,beg[MAXN],nex[MAXN<<1],to[MAXN<<1],was[MAXN<<1],d[MAXN],nd[MAXN],tp,ansp[MAXN],sum,path[MAXN<<1],use[MAXN<<1],cnt,fa[MAXN],pre;
    struct node{
    	int u,v,id;
    };
    node side[MAXN];
    std::vector<int> G[MAXN];
    std::map<int,int> M[MAXN];
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char ch='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(ch!='')putchar(ch);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline void insert(int x,int y,int z)
    {
    	to[++e]=y;
    	nex[e]=beg[x];
    	beg[x]=e;
    	was[e]=z;
    }
    inline int found(int x)
    {
    	if(fa[x]!=x)fa[x]=found(fa[x]);
    	return fa[x];
    }
    inline void dfs(int x,int f)
    {
    	for(register int i=0,lt=G[x].size();i<lt;++i)
    		if(G[x][i]==f)continue;
    		else dfs(G[x][i],x);
    	if(x==1)return ;
    	if(nd[x]&1)insert(x,f+n,M[x][f]),insert(f+n,x,M[x][f]),nd[x]++;
    	else insert(x+n,f,M[x][f]),insert(f,x+n,M[x][f]),nd[f]++;
    }
    inline void eulerdfs(int x)
    {
    	for(register int &i=beg[x];i;i=nex[i])
    		if(!use[i]&&!use[i^1])
    		{
    			int tmp=i;
    			use[i]=use[i^1]=1;
    			eulerdfs(to[i]);
    			path[++cnt]=tmp;
    		}
    }
    int main()
    {
    	read(n);read(m);
    	for(register int i=1;i<=m;++i)
    	{
    		int u,v;read(u);read(v);
    		d[u]++;d[v]++;
    		side[i]=(node){u,v,i};
    	}
    	for(register int i=1;i<=n;++i)
    	{
    		fa[i]=i;
    		if(d[i]&1)insert(0,i,m+i),insert(i,0,m+i),nd[i]++;
    	}
    	for(register int i=1;i<=m;++i)
    	{
    		int u=found(side[i].u),v=found(side[i].v);
    		if(u==v)insert(side[i].u,side[i].v+n,side[i].id),insert(side[i].v+n,side[i].u,side[i].id),nd[side[i].u]++;
    		else G[side[i].u].push_back(side[i].v),G[side[i].v].push_back(side[i].u),M[side[i].u][side[i].v]=M[side[i].v][side[i].u]=side[i].id,fa[u]=v;
    	}
    	dfs(1,0);
    	eulerdfs(0);
    	while(cnt)
    	{
    		while(cnt&&!to[path[cnt]])cnt--;
    		if(cnt<=0)break;
    		sum=0;pre=to[path[cnt]];
    		int ps=cnt;
    		while(ps&&to[path[ps]])sum++,ps--;
    		printf("%d %d %d
    ",pre,to[path[ps+1]],sum-1);
    		for(register int i=cnt-1;i>ps;--i)printf("%d ",was[path[i]]);puts("");
    		cnt=ps;
    	}
    	return 0;
    }
    
  • 相关阅读:
    使用golang访问kubebernetes
    使用 Rancher 管理现有 Kubernetes 集群
    Running powershell scripts during nuget package installation and removal
    How to Create, Use, and Debug .NET application Crash Dumps in 2019
    寻找写代码感觉(一)之使用 Spring Boot 快速搭建项目
    Selenium+Java之解决org.openqa.selenium.InvalidArgumentException: invalid argument报错问题
    Selenium环境搭建
    关于Xpath定位方法知道这些基本够用
    Web自动化之浏览器启动
    【翻译】编写代码注释的最佳实践
  • 原文地址:https://www.cnblogs.com/hongyj/p/9484241.html
Copyright © 2011-2022 走看看