1. 程式人生 > >尤拉圖 HDU 3018

尤拉圖 HDU 3018

題意:

 

Problem Description

Ant Country consist of N towns.There are M roads connecting the towns.

Ant Tony,together with his friends,wants to go through every part of the country. 

They intend to visit every road , and every road must be visited for exact one time.However,it may be a mission impossible for only one group of people.So they are trying to divide all the people into several groups,and each may start at different town.Now tony wants to know what is the least groups of ants that needs to form to achieve their goal.

 

 

Input

Input contains multiple cases.Test cases are separated by several blank lines. Each test case starts with two integer N(1<=N<=100000),M(0<=M<=200000),indicating that there are N towns and M roads in Ant Country.Followed by M lines,each line contains two integers a,b,(1<=a,b<=N) indicating that there is a road connecting town a and town b.No two roads will be the same,and there is no road connecting the same town.

 

 

Output

For each test case ,output the least groups that needs to form to achieve their goal.

 

 

Sample Input

 

3 3

1 2

2 3

1 3

 

 

4 2

1 2

3 4

 

 

Sample Output

 

1

2

分析:

題意等價於:

        給你無向圖的N個點和M條邊,保證這M條邊都不同且不會存在同一點的自環邊,現在問你至少要幾筆才能所有邊都畫一遍.(一筆畫的時候筆不離開紙)

分析:

        首先根據給出的邊我們只需要分別處理每個連通分量需要多少筆即可.

        如果該連通分量是一個孤立的點,顯然只需要0筆.

        如果該連通分量是一個尤拉圖或半尤拉圖,只需要1筆.

        現在關鍵是連通分量並非一個(半)尤拉圖時,需要幾筆?

        一般性的結論是:

       非(半)尤拉圖需要的筆數==該圖中奇數度的點數目/2(證明請看---->https://blog.csdn.net/u013480600/article/details/30285541
程式碼:

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=100000+10;
int n,m;
int fa[maxn];
int num[maxn],odd[maxn],degree[maxn];
int findset(int i)
{
    if(fa[i]==-1) return i;
    return fa[i]=findset(fa[i]);
}
int main()
{
    while(scanf("%d%d",&n,&m)==2)
    {
        memset(fa,-1,sizeof(fa));
        memset(num,0,sizeof(num));
        memset(odd,0,sizeof(odd));
        memset(degree,0,sizeof(degree));
        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&v,&u);//這裡u,v顛倒一樣。
            degree[v]++;
            degree[u]++;
            u=findset(u), v=findset(v);
            if(u!=v) fa[u]=v;
        }
        for(int i=1;i<=n;i++)
        {
            num[findset(i)]++;      //num[i]=x表以i為根的連通分量中有x個節點
/*這裡可能不好理解,舉個例子3個點兩條邊(1->2,1->3按並查集建樹)
nump[findest(1)]即num[3]++;
num[findest(2)]即num[3]++;所以以三為根的節點有3個,
這裡要注意3所包括的節點(3除外)的聯通節點有0個,
即num[2]=0,num[1]=0.仔細想想就知道了。
*/
            if(degree[i]%2) odd[findset(i)]++;//odd[i]=x表以i為根的連通分量中有x個奇度的點
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            if(num[i]<=1) continue;
            else if(odd[i]==0) ans++;
            else if(odd[i]>0) ans+=odd[i]/2;
        }
        printf("%d\n",ans);
    }
    return 0;
}