题意:
你有一个无向连通图,边的总数为偶数。
设图中有k个奇点(度数为奇数的点),你需要把它们配成k/2个点对(显然k被2整除)。对于每个点对(u,v),你需要用一条长度为偶数(假设每条边长度为1)的路径将u和v连接。每条路径允许经过重复的点,但不允许经过重复的边。这k/2条路径之间也不能有重复的边。
题解:
假如没有长度为偶数这个限制,那么就新建一个点,将所有奇数点连起来,跑欧拉回路即可。
现在要求长度为偶数,可以将一个点拆成两个点,
i
,
i
+
n
i,i+n
i,i+n,对于一条边,要么
x
−
>
y
+
n
x->y+n
x−>y+n,要么
y
−
>
x
+
n
y->x+n
y−>x+n,这样就能保证
x
−
>
y
x->y
x−>y的路径长度为偶数。
但是还要保证构造出来的图有欧拉回路,即每个点的度数为偶数。
首先找一棵生成树,非树边就随便连,对于树边
x
−
>
f
a
x->fa
x−>fa假如x度数为偶数则连
x
+
n
>
f
a
x+n>fa
x+n>fa否则连
f
a
+
n
−
>
x
fa+n->x
fa+n−>x这样x和x+n的度数都一定是偶数。
但是根节点似乎不能得到保证,容易发现,
1
,
n
+
1
1,n+1
1,n+1奇偶性相同,假如同为奇,一定存在一条以
1
,
n
+
1
1,n+1
1,n+1为起点终点的欧拉路径。因为原图有偶数条边,而从左点集出发经过偶数条边一定会回到左点集,矛盾。所以
1
,
n
+
1
1,n+1
1,n+1必定同为偶。
对新图求欧拉回路即可。
code:
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n,m;
vector<int> v[1000010],vc[1000010];
struct node{
int x,y,next,c;
}e[1000010],a[1000010];int len=0,last[1000010];
int fa[1000010],d[1000010],cnt[1000010];
void ins(int x,int y,int c)
{
a[++len].y=y;a[len].c=c;
a[len].next=last[x];last[x]=len;
cnt[x]++;
}
int findfa(int x) {return fa[x]==x?fa[x]:fa[x]=findfa(fa[x]);}
void bt(int x,int fa,int fr)
{
for(int i=0;i<v[x].size();i++)
if(v[x][i]!=fa) bt(v[x][i],x,vc[x][i]);
if(x==1) return;
if(cnt[x]&1) ins(x,fa+n,fr),ins(fa+n,x,fr);
else ins(x+n,fa,fr),ins(fa,x+n,fr);
}
int sta[1000010],top=0;
bool vis[1000010];
void dfs(int x)
{
for(int &i=last[x];i;i=a[i].next)
{
while(i&&vis[a[i].c]) i=a[i].next;
if(!i) return;
vis[a[i].c]=true;
int k=i;dfs(a[i].y);
sta[++top]=a[k].c;
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&e[i].x,&e[i].y);
d[e[i].x]++;d[e[i].y]++;
}
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=n;i++)
if(d[i]&1) ins(0,i,i+m),ins(i,0,i+m);
for(int i=1;i<=m;i++)
{
int x=e[i].x,y=e[i].y,tx=findfa(x),ty=findfa(y);
if(tx==ty) ins(x,y+n,i),ins(y+n,x,i);
else
{
fa[tx]=ty;
v[x].push_back(y);vc[x].push_back(i);
v[y].push_back(x);vc[y].push_back(i);
}
}
memset(vis,false,sizeof(vis));
bt(1,0,0);dfs(0);
//printf("ok\n");
//for(int i=1;i<=top;i++) printf("%d ",sta[i]);printf("\n");
while(top)
{
int ans1,ans2;
ans1=sta[top--]-m;
//printf("top:%d\n",top);
int j=top;
while(sta[j]<=m)
{
//printf("%d %d\n",j,sta[j]);
j--;
}
ans2=sta[j]-m;
//printf("j:%d\n",j);
printf("%d %d %d\n",ans1,ans2,top-j);
while(top>j) printf("%d ",sta[top--]);putchar('\n');
top--;
}
}