1. 程式人生 > >Gym 101879C Promenade by the lake —— dfs+並查集 找構成歐拉回路需要新增的邊

Gym 101879C Promenade by the lake —— dfs+並查集 找構成歐拉回路需要新增的邊

The city of Porto will host the ICPC World Finals in 2019. One of the secret touristic spots in the city is the so-called “lake of the thousand bridges”. Mr. Manoel Pontes (Pontes stands for “bridges” in Portuguese; this is amazingly his real name…) built this wonder in the lake with a lifetime of hard work. The lake has many small islands. Mr. Manoel built small wooden bridges connecting the islands. In some cases, there are multiple bridges connecting some pairs of islands. Visitors enjoy themselves while promenading through the bridges and small islands. Besides, by walking through the bridges the visitors can go from one island to any other island.

Mr. Manoel wants to enhance this touristic attraction to get even more visitors. One of this ideas is to organize visitors games. He plans to have the following challenge: is it possible to start to walk from outside the lake, pass through all the bridges without repetition, and go back to the starting point (that is, back out of the lake)?

Before creating the attraction, he himself tried it over and over but could not find out if this was possible. To make the challenge even more interesting, Mr. Manoel will allow adding some bridges between some islands. He wants to know if, by adding some of these bridges, the walk he wants the game to have becomes possible. Your task in this problem is to decide if it is possible to choose some (possibly none) of these bridges that, when added, allow people to walk as described.

Input The first line has three integers N, M and K, where N is the number of islands, M is the number of already built bridges and K is the number of bridges that is possible to add. The islands are represented by distinct integers from 1 to N. Each one of the following M+K lines describes a bridge. Each one of them has two integers, a and b, that represent the existence or possibility of adding a bridge between islands a and b. The first M lines describe bridges that already exist and the next K lines describe bridges that you may add.

Constraints

1≤N≤3⋅105 0≤M,K≤3⋅105 1≤a<b≤N You may assume that we can go from one island to any other island by using only the bridges already built. Output In the first line print “YES” (without the quotes), if such a walk is possible or “NO” otherwise. If there is a solution, print in the second line an integer R, 0≤R≤K that is the number of bridges that need to be added. Next print R lines, each one with two integers, the islands that are connected by this bridge, in any order. If there are multiple solutions, any one will be accepted.

Examples Input 4 3 4 1 2 2 3 3 4 1 4 1 4 1 3 3 4 Output YES 1 1 4 Input 4 3 2 1 2 2 3 3 4 1 2 3 4 Output NO

題意:

給你n個點,m條已經連成的邊和k條可選邊,問你需要從k裡面取出那些才能構成一個歐拉回路

題解:

歐拉回路就是從起點開始每條邊都走一遍最後回到起點,由此可以推出所有邊的度都是偶數的。 易證如果可以通過新增邊來構成歐拉回路那麼奇數邊的點一定是偶數個。 接下來怎麼找有哪些邊呢,我們可以知道如果有一條可選邊的左右奇數頂點是奇數個的,那麼這條邊一定要連,因為兩塊內部可能無法自己連成歐拉回路,原因剛才講過了,如果這條邊左右是偶數的話,那麼這條邊就不用連,舉個例子:1-2-3-4和5-2-3-6,那麼1-2-5和4-3-6就可以連起來,不再需要2-3這條邊,那麼我們for一遍所有點並dfs即可。

#include<bits/stdc++.h>
using namespace std;
#define pa pair<int,int>
#define mp(a,b) make_pair(a,b)
const int N=3e5+5;
int fa[N],num[N],ctans;
pa ans[N];
struct node
{
    int to,next;
}e[N*2];
int head[N],cnt;
void add(int x,int y)
{
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt++;
}
int finds(int x)
{
    return x==fa[x]?fa[x]:fa[x]=finds(fa[x]);
}
int siz[N];
void match(int x,int y)
{
    int fax=finds(x);
    int fay=finds(y);
    if(fax!=fay)
    {
        fa[fay]=fax;
        siz[fax]+=siz[fay];
    }
}
int vis[N];
void dfs(int f)
{
    vis[f]=1;
    for(int i=head[f];~i;i=e[i].next)
    {
        int son=e[i].to;
        if(!vis[son])
        {
            dfs(son);
            num[f]+=num[son];
            if(num[son]%2)
                ans[++ctans]=mp(f,son);
        }
    }
}
int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    memset(head,-1,sizeof(head));
    int f,s;
    for(int i=1;i<=n;i++)
        fa[i]=i,num[i]=0;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&f,&s);
        num[f]++,num[s]++;
    }
    for(int i=1;i<=n;i++)
        siz[i]=num[i];
    for(int i=1;i<=k;i++)
    {
        scanf("%d%d",&f,&s);
        add(f,s),add(s,f),match(f,s);
    }
    //for(int i=1;i<=n;i++)
        //cout<<num[i]<<endl;
    //for(int i=head[1];~i;i=e[i].next)
    //cout<<1<<" "<<e[i].to<<endl;
    for(int i=1;i<=n;i++)
    {
        if(fa[i]==i)
        {
            if(siz[i]%2)
            {
                printf("NO\n");
                return 0;
            }
            dfs(i);
        }
    }
    printf("YES\n");
    printf("%d\n",ctans);
    for(int i=1;i<=ctans;i++)
        printf("%d %d\n",ans[i].first,ans[i].second);
    return 0;
}