[省选前题目整理][CodeForces 527E]Data Center Drama(欧拉回路+构造)

来源:互联网 发布:淘宝助手官方网站 编辑:程序博客网 时间:2024/05/17 01:11

题目链接

http://codeforces.com/contest/527/problem/E

思路

非常不错的一道图论的构造题。
注意到最终的图是一个欧拉回路,那么每个点最终的入度等于出度,如果这个欧拉回路长是偶数的话,就相当于把这个图变成无向图(所有边加上反向边),并且新图的每个点的度数均为偶数。因此我们就需要在原图中,对于所有度数为奇数的点,依次连无向边,这样原图就变成了所有点度数均为偶数了,然后再对这个无向图,随便找个起点做欧拉回路,得到这个欧拉回路的路径,要把这个无向图的欧拉回路变成一个有向图的欧拉回路就很容易了,假如原来无向图的欧拉回路是a-b-c-d-e这样的形式,只需要把它变成a->b<-c->d<-e……这样的形式,就是给原来的无向图的每条边确定了方向,这样做把每个点在无向图中的偶数的度数均匀地分成了一半出度、一半入度,构造出的新有向图就是一个欧拉回路 了,但是前提就是这个欧拉回路的长度为偶数,这是很显然的。
那么如果把奇数度数点依次加完边后无向边总数为奇数怎么办?随便找个点加自环即可。

但是此题还有很重要的一点需要注意:做欧拉回路时,如果不做优化,把之前访问过的废边都访问的话,整个程序的复杂度就是∑degree[i]2,会TLE,因此要在做欧拉回路时,每访问完一条边,就把这条边删掉,最好实现的方式就是用multiset当作邻接表存边了(因为有自环所以不能用set),另外自环的边也是要加两遍的。

代码

#include <iostream>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <algorithm>#include <set>#include <vector>#define MAXV 610000using namespace std;vector<int>odd,ans;multiset<int>G[MAXV];int tot_edge=0;int degree[MAXV]; //每个点的度inline void AddEdge(int U,int V){    G[U].insert(V);}void DFS(int u){    while(!G[u].empty())    {        int v=*G[u].begin();        G[u].erase(G[u].begin());        G[v].erase(G[v].find(u));        DFS(v);    }    ans.push_back(u);}int main(){    int n,m;    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++)    {        int u,v;        scanf("%d%d",&u,&v);        AddEdge(u,v),tot_edge++;        AddEdge(v,u);        degree[v]++,degree[u]++;    }    for(int i=1;i<=n;i++)        if(degree[i]&1)            odd.push_back(i);    for(int i=0;i<(int)odd.size();i+=2)    {        int u=odd[i],v=odd[i+1];        AddEdge(u,v),tot_edge++;        AddEdge(v,u);    }    if(tot_edge&1) //需要加一条自环边        tot_edge++,AddEdge(1,1),AddEdge(1,1);    DFS(1);    printf("%d\n",tot_edge);    for(int i=0;i<(int)ans.size()-1;i++)    {        if(i&1) printf("%d %d\n",ans[i],ans[i+1]);        else printf("%d %d\n",ans[i+1],ans[i]);    }    return 0;}
0 0
原创粉丝点击