【欧拉回路+DFS】GYM - 229073 - C. Promenade by the lake

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/monochrome00/article/details/82837846

题目链接<http://codeforces.com/gym/229073/problem/C>


题意:

有一张无向连通图,添加若干条边使图存在欧拉回路。输出任意一种方案。


题解:

  • 无向图存在欧拉回路的判断条件是所有点的度数为偶数。
  • 所以最后的添边方案应该满足:度为奇数的连奇数条边,度为偶数的连偶数条边。
  • 考虑新加的一条链如:1—2—3—4—5,那么链的两端度数加1,链的中间度数加2。所以可以考虑构造从奇数点出发并且以奇数点结束的链。而如果有一些边被重复利用如:1—2—3—4,5—2—3—6,也可以把这两条链变成:1—2—5,4—3—6。
  • 对于一个连通块,如果奇数点的个数为奇数个,那么不可能构造出来,直接输出NO即可。
  • 至于构造的方法可以用dfs建树搜索:搜索每一个点下的子树,如果子树的度数为奇数,那么就连一条边。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+7;
struct Edge{
    int u,v,nxt;
    Edge(int u=0,int v=0,int nxt=0):u(u),v(v),nxt(nxt){}
}e[N*2];
bool tr[N*2];
int p[N],edn;
void add(int u,int v){
    e[++edn]=Edge(u,v,p[u]);p[u]=edn;
    e[++edn]=Edge(v,u,p[v]);p[v]=edn;
}
int n,m,k,u,v;
int d[N],ds[N],dt[N],vis[N];
int f[N];
int fd(int x){return x==f[x]?x:f[x]=fd(f[x]);}
void un(int x,int y){
    int fx=fd(x),fy=fd(y);
    if(fx==fy) return;
    f[fx]=fy;
    ds[fy]+=ds[fx];
}
vector<int>ans;
void dfs(int u){
    dt[u]=d[u];
    vis[u]=1;
    for(int i=p[u];~i;i=e[i].nxt){
        int v=e[i].v;
        if(vis[v]) continue;
        dfs(v);
        if(dt[v]&1){
            dt[u]+=dt[v];
            ans.push_back(i/2*2);
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        d[u]=d[u]^1,d[v]=d[v]^1;
    }
    for(int i=1;i<=n;i++) f[i]=i,ds[i]=d[i];
    memset(p,-1,sizeof(p));edn=-1;
    for(int i=1;i<=k;i++){
        scanf("%d%d",&u,&v);
        un(u,v);
        add(u,v);
    }
    for(int i=1;i<=n;i++){
        if(fd(i)!=i) continue;
        if(ds[i]&1){
            printf("NO\n");
            return 0;
        }
        dfs(i);
    }
    int sz=ans.size();
    printf("YES\n%d\n",sz);
    for(int i=0;i<sz;i++)
        printf("%d %d\n",e[ans[i]].u,e[ans[i]].v);
}

猜你喜欢

转载自blog.csdn.net/monochrome00/article/details/82837846
今日推荐