1. 程式人生 > >BZOJ2935: [Poi1999]原始生物(歐拉回路)

BZOJ2935: [Poi1999]原始生物(歐拉回路)

2935: [Poi1999]原始生物

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 150  Solved: 71
[Submit][Status][Discuss]

Description

原始生物的 遺傳密碼是一個自然數的序列K=(a 1,...,a n)。原始生物的 特徵是指在遺傳密碼中連續出現的數對(l,r),即存在自然數i使得l=a i且r=a i+1。在原始生物的遺傳密碼中不存在(p,p)形式的特徵。 求解任務:
請設計一個程式:        ·讀入一系列的特徵。        ·計算包含這些特徵的最短的遺傳密碼。         ·將結果輸出

Input

 第一行是一個整數n ,表示特徵的總數。在接下來的n行裡,每行都是一對由空格分隔的自然數l 和r ,1 <= l,r <= 1000。數對(l, r)是原始生物的特徵之一。輸入檔案中的特徵不會有重複。

Output

唯一一行應該包含一個整數,等於包含了PIE.IN中所有特徵的遺傳密碼的最小長度。

Sample Input

12
2 3
3 9
9 6
8 5
5 7
7 6
4 5
5 1
1 4
4 2
2 8
8 6

Sample Output

15

注:
PIE.IN中的所有特徵都包含在以下遺傳密碼中:
(8, 5, 1, 4, 2, 3, 9, 6, 4, 5, 7, 6, 2, 8, 6)

HINT

 

思路:如果是個歐拉回路,一筆畫的最少用邊數就是邊+0,點就是邊+1;否則,最少的邊數=邊+奇數點/2-1,點就是邊+奇數點/2;

所以最後答案=邊數+歐拉回路數+度數為奇數/2;

(非歐拉回路的一筆畫最小邊數=邊+奇數點/2-1,是因為我們可以把奇數點兩兩配對,然後求一個歐拉回路,最後隨便刪去一條邊。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=1010;
int d[maxn],vis[maxn],fa[maxn],sum[maxn],ans,A,B;
int find(int x){
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
int main()
{
    int N,x,y; scanf("%d",&N);
    rep(i,1,1000) fa[i]=i;
    rep(i,1,N) {
        scanf("%d%d",&x,&y);
        d[x]++; d[y]--; vis[x]=vis[y]=1;
        fa[find(x)]=find(y);
    }
    rep(i,1,1000) {
        if(vis[i]){
            int f=find(i);
            sum[f]+=d[i]>=0?d[i]:-d[i];
        }
    }
    rep(i,1,1000){
        if(vis[i]&&find(i)==i){
            if(sum[i]==0) A++;
            else B+=sum[i];
        }
    }
    printf("%d\n",N+A+B/2);
    return 0;
}