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;
    }
    
  • 相关阅读:
    Asp.net MVC 视图引擎集合
    技术债务管理计划
    Android应用程序反编译
    Managed Extensibility Framework(MEF) 2 框架新特性介绍
    企业搜索引擎开发之连接器connector(十四)
    企业搜索引擎开发之连接器connector(十)
    企业搜索引擎开发之连接器connector(十一)
    zookeeper 原理
    企业搜索引擎开发之连接器connector(十二)
    jspf插件框架
  • 原文地址:https://www.cnblogs.com/hongyj/p/9484241.html
Copyright © 2011-2022 走看看