1. 程式人生 > >【歐拉回路+DFS】GYM - 229073 - C. Promenade by the lake

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

題目連結<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);
}