BZOJ3724PA2014Final Krolestwo——欧拉回路+构造
题目描述
你有一个无向连通图,边的总数为偶数。
设图中有k个奇点(度数为奇数的点),你需要把它们配成k/2个点对(显然k被2整除)。对于每个点对(u,v),你需要用一条长度为偶数(假设每条边长度为1)的路径将u和v连接。每条路径允许经过重复的点,但不允许经过重复的边。这k/2条路径之间也不能有重复的边。
输入
第一行有两个整数n,m(2<=n,m<=250000),分别表示点数、边数,m为偶数。
接下来m行,每行两个整数a,b(1<=a,b<=n,a≠b),表示a,b间连有一条边。不存在重边。保证奇点的数目不为零。
输出
如果你认为无解就输出NIE。
设图中有k个奇点,则输出由k/2部分组成,每个部分包含两行:第一行为u,v,l,表示连接的两个点,及路径长度。第二行为空格隔开的l个整数,表示u到v的路径。边按照输入顺序从1到m编号。
若有多组答案,任意输出其中一个。
样例输入
1 2
2 3
3 4
4 5
5 6
6 1
1 4
2 5
样例输出
1 5 2
6 5
2 4 2
8 4
另一种合法输出:
1 5 6
1 2 3 7 6 5
2 4 2
8 4
根据题目给出的路径没有重边的要求,我们可以尝试找出原图的一个欧拉回路,这样就能满足路径没有重复边的条件了。要使原图有欧拉回路就要保证没有奇度数点,我们新建一个点$x$,将它连边向所有奇度数点,这样就能保证原图有欧拉回路了。但这样还是不能保证每个路径都有偶数条边,我们将原图拆点建新图将一个点$u$拆成$u_{A},u_{B}$两个点,将原图边$(u,v)$变为$(u_{A},v_{B})$或$(u_{B},v_{A})$(具体如何连下面再说)。将所有原图奇度数点$u$在新图中连边$(u_{A},x)$,这样就保证了新图中一条边的两端点下标不同(即一定有一个$A$一个$B$),而任意一对$A$点之间的任意路径都有偶数条边。对于原图的边我们找出原图的任意一棵生成树,对于不在生成树上的边随便连上述哪种都行,然后我们规定一个生成树的根,从叶子结点往上倒推出每个点连向父亲的边是$(u_{A},v_{B})$还是$(u_{B},v_{A})$。因为原图边数为偶数,所有这样连完显然是可以保证每个点度数为偶数。因为只需要配对原图奇度数的点,也就是新图中与$x$相连的点,我们从$x$开始$dfs$,并记录沿途边的编号并打上访问标记,到一个点时只要有没标记的出边就可以走下去,当再一次走到$x$时就说明匹配了一对点。这样不断走下去,当$x$的出边都被标记时就说明所有点对都匹配完毕。这也就是说实际上我们并不需要求出新图的一个欧拉回路。有一点需要注意的是因为$dfs$找路径时走过的边就不会再走了,而每个点可能会被遍历许多次,所以,每次走完的边都要在链式前向星上删除掉,否则会被卡。
这里有两个版本供大家选择
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<cstdio> #include<bitset> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define pr pair<int,int> using namespace std; char *p1,*p2,buf[100000]; #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++) int read() {int x=0; char c=nc(); while(c<48) c=nc(); while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x;} vector<pr>v[250010]; int vis[500010]; int to[1000010]; int head[500010]; int next[1000010]; int q[500010]; int num[10000010]; int cnt; int S,T; int n,m; int x,y; int d[250010]; int dep[250010]; int r[250010]; int tot=1; void add(int x,int y,int id) { next[++tot]=head[x]; head[x]=tot; to[tot]=y; num[tot]=id; } void dfs(int x,int fa,int num) { dep[x]=dep[fa]+1; int len=v[x].size(); for(int i=0;i<len;i++) { int to=v[x][i].first; if(!dep[to]) { dfs(to,x,v[x][i].second); } else if(dep[to]>dep[x]) { r[x]^=1; add(x<<1,to<<1|1,v[x][i].second); add(to<<1|1,x<<1,v[x][i].second); } } if(r[x]) { r[x]^=1; add(x<<1,fa<<1|1,num); add(fa<<1|1,x<<1,num); } else { r[fa]^=1; add(x<<1|1,fa<<1,num); add(fa<<1,x<<1|1,num); } } void dfs2(int x) { if(x==1) { if(cnt) { printf("%d %d %d\n",S,T,cnt); for(int i=1;i<=cnt;i++) { printf("%d ",q[i]); } printf("\n"); } cnt=S=T=0; } else { T=x>>1; if(!S) { S=x>>1; } } while(1) { int i=head[x]; if(!i) { break; } head[x]=next[i]; if(vis[i>>1]) { continue; } vis[i>>1]=1; if(num[i]) { q[++cnt]=num[i]; } dfs2(to[i]); } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); v[x].push_back(make_pair(y,i)); v[y].push_back(make_pair(x,i)); d[x]++,d[y]++; } for(int i=1;i<=n;i++) { r[i]=d[i]&1; if(d[i]&1) { add(1,i<<1,0); add(i<<1,1,0); } } dfs(1,0,0); dfs2(1); }
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<cstdio> #include<bitset> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #define pr pair<int,int> using namespace std; vector<pr>v[500010]; int vis[500010]; int to[1000010]; int head[500010]; int next[1000010]; int q[500010]; int num[10000010]; int cnt; int S,T; int n,m; int x,y; int d[500010]; int dep[500010]; int r[500010]; int f[500010]; int tot=1; int find(int x) { if(f[x]==x) { return x; } return f[x]=find(f[x]); } void add(int x,int y,int id) { next[++tot]=head[x]; head[x]=tot; to[tot]=y; num[tot]=id; r[x]++; } void dfs(int x,int fa,int num) { int len=v[x].size(); for(int i=0;i<len;i++) { if(v[x][i].first!=fa) { dfs(v[x][i].first,x,v[x][i].second); } } if(fa) { if(r[x]&1) { add(x,fa+n,num); add(fa+n,x,num); } else { add(x+n,fa,num); add(fa,x+n,num); } } } void dfs2(int x) { while(1) { int i=head[x]; if(i==-1) { break; } head[x]=next[i]; if(vis[i>>1]) { continue; } vis[i>>1]=1; dfs2(to[i]); q[++cnt]=num[i]; } } int main() { scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++) { f[i]=i; } for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); d[x]++,d[y]++; int fx=find(x); int fy=find(y); if(fx!=fy) { f[fx]=fy; v[x].push_back(make_pair(y,i)); v[y].push_back(make_pair(x,i)); } else { add(x,y+n,i); add(y+n,x,i); } } for(int i=1;i<=n;i++) { if(d[i]&1) { add(0,i,m+i); add(i,0,m+i); } } dfs(1,0,0); dfs2(0); while(cnt) { S=q[cnt--]-m; int i=cnt; while(q[i]<=m&&i>1)i--; T=q[i]-m; printf("%d %d %d\n",S,T,cnt-i); for(int j=cnt;j>i;j--) { printf("%d ",q[j]); } printf("\n"); cnt=i-1; } }