1. 程式人生 > 其它 >[HDU 2454] Degree Sequence of Graph G(Havel定理 度序列判斷可簡單圖化)

[HDU 2454] Degree Sequence of Graph G(Havel定理 度序列判斷可簡單圖化)

技術標籤:刷題演算法圖論

Degree Sequence of Graph G

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=2454

Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Problem Description

Wang Haiyang is a strong and optimistic Chinese youngster. Although born and brought up in the northern inland city Harbin, he has deep love and yearns for the boundless oceans. After graduation, he came to a coastal city and got a job in a marine transportation company. There, he held a position as a navigator in a freighter and began his new life.

The cargo vessel, Wang Haiyang worked on, sails among 6 ports between which exist 9 routes. At the first sight of his navigation chart, the 6 ports and 9 routes on it reminded him of Graph Theory that he studied in class at university. In the way that Leonhard Euler solved The Seven Bridges of Knoigsberg, Wang Haiyang regarded the navigation chart as a graph of Graph Theory. He considered the 6 ports as 6 nodes and 9 routes as 9 edges of the graph. The graph is illustrated as below.

在這裡插入圖片描述

According to Graph Theory, the number of edges related to a node is defined as Degree number of this node.

Wang Haiyang looked at the graph and thought, If arranged, the Degree numbers of all nodes of graph G can form such a sequence: 4, 4, 3,3,2,2, which is called the degree sequence of the graph. Of course, the degree sequence of any simple graph (according to Graph Theory, a graph without any parallel edge or ring is a simple graph) is a non-negative integer sequence?

Wang Haiyang is a thoughtful person and tends to think deeply over any scientific problem that grabs his interest. So as usual, he also gave this problem further thought, As we know, any a simple graph always corresponds with a non-negative integer sequence. But whether a non-negative integer sequence always corresponds with the degree sequence of a simple graph? That is, if given a non-negative integer sequence, are we sure that we can draw a simple graph according to it.?

Let’s put forward such a definition: provided that a non-negative integer sequence is the degree sequence of a graph without any parallel edge or ring, that is, a simple graph, the sequence is draw-possible, otherwise, non-draw-possible. Now the problem faced with Wang Haiyang is how to test whether a non-negative integer sequence is draw-possible or not. Since Wang Haiyang hasn’t studied Algorithm Design course, it is difficult for him to solve such a problem. Can you help him?

Input

The first line of input contains an integer T, indicates the number of test cases. In each case, there are n+1 numbers; first is an integer n (n<1000), which indicates there are n integers in the sequence; then follow n integers, which indicate the numbers of the degree sequence.

Output

For each case, the answer should be "yes"or “no” indicating this case is “draw-possible” or “non-draw-possible”

Sample Input

2
6 4 4 3 3 2 2
4 2 1 1 1

Sample Output

yes
no

Source

2008 Asia Regional Harbin

思路

題意:給出一個無向圖的頂點度序列 {dn},要求判斷能否構造出一個簡單無向圖。
Havel定理 :https://baike.baidu.com/item/Havel%E5%AE%9A%E7%90%86?fr=aladdin

定義:給出一個無向圖的頂點度序列 {dn},要求判斷能否構造出一個簡單無向圖。 分析:
貪心的方法是每次把頂點按度大小從大到小排序,取出度最大的點
V i V_i Vi ,依次和度較大的那些頂點 V j V_j Vj 連線,同時減去 V j V_j Vj
的度。連線完之後就不再考慮 V i V_i Vi了,剩下的點再次排序然後找度最大的去連線……這樣就可以構造出一個可行解。
判斷無解有兩個地方,若某次選出的 V i V_i Vi
的度比剩下的頂點還多,則無解;若某次 V j V_j Vj的度減成了負數,則無解。
至於什麼是Havel定理,上面這個構造過程就是了

定理的簡單證明如下:
必要(<=)若d’可簡單圖化,我們只需把原圖中的最大度點和d’中度最大的d1個點連邊即可,易得此圖必為簡單圖。
充分(=>)若d可簡單圖化,設得到的簡單圖為G。分兩種情況考慮:
(a)若G中存在邊,則把這些邊除去得簡單圖G’,於是d’可簡單圖化為G’
(b)若存在點Vi,Vj使得i=dj,必存在k使得(Vi, Vk)在G中但( V j V_j Vj, V k V_k Vk)不在 G 中。這時我們可以令GG=G-{( V i V_i Vi, V k V_k Vk),( V 1 V_1 V1, V j V_j Vj)}+{( V k V_k Vk, V j V_j Vj),( V 1 V_1 V1, V i V_i Vi)}。GG的度序列仍為d,我們又回到了情況(a)。

Havel-Hakimi定理:
給定一個非負整數序列{d1,d2,…dn},若存在一個無向圖使得圖中各點的度與此序列一一對應,則稱此序列可圖化。進一步,若圖為簡單圖,則稱此序列可簡單圖化。

定理描述:
由非負整陣列成的有限非遞增序列,S={d1,d2,d3…dn},當且僅當S1={d2-1,d3-1…d(d1+1),d(d1+2)…dn}也是可圖的,也就是說,序列S1也是由非負整陣列成的有限非遞增序列,S1是由S的刪除第一個元素d1之後的前d1個元素分別減一後得到的序列。

舉例:

判斷 4 4 3 3 2 是否可圖化

首先按非增序列排列 4 4 3 3 2

刪除4,然後把前4大的數-1 變為:3 2 2 1

然後刪除3,把前3大的數-1 變為:1 1 0

刪除1,把前1大的數刪除 變為:1 0

刪除1,把前1大的數刪除 變為: 0

所以是可圖化的

判斷 5 4 5 2 3 1 是否可圖化

首先按非升序排列 5 5 4 3 2 1

刪除5,然後把前5大的數-1 變為:4 3 2 1 0

然後刪除4,把前4大的數-1 變為:3 2 1 -1

出現了負數,不可圖化

判斷 9 4 5 2 3 1 是否可圖化

首先按非升序排列 9 5 4 3 2 1

刪除9,然後把前9大的數-1 ,但數不夠前9大,

也就是會出現負數

不可圖化

沒有自環沒有重邊的圖叫做簡單圖。
  如果一個度數序列存在一張無向圖滿足這個度數序列則稱這個度數序列可圖化。如果這張圖是簡單圖,則稱這個度數序列是可簡單圖化。
  對於可圖化的判定,我們只需要判斷是否 ∑ d e g [ i ] m o d 2 = = 0 ∑deg[i] mod2==0 deg[i]mod2==0即可。關於具體圖的構造,我們可以簡單地把奇數度的點配對,剩下的全部搞成自環。
  對於可簡單圖化的判定就是Heavel定理的內容了。簡單的說,把序列d排序後,找出度最大的點(設度為d1),把它與度次大的d1個點之間連邊,然後這個點就可以不管了,一直繼續這個過程,直到建出完整的圖,或出現負度或剩下的節點數小於當前點剩餘度數。

程式碼

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

#define N 1010
int a[N];
bool cmp(int a, int b)
{
    return a > b;
}

int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        int n;
        cin >> n;
        int sum = 0;
        for (int i = 0; i < n; i++)
        {
            cin >> a[i];
            sum += a[i];
        }
        if (sum % 2) {
            cout << "no" << endl;
            continue;
        }
        else {
            sort(a, a + n, cmp);
            int flag = 0;
            for (int i = 0; i < n - 1; i++) //去掉第i個
            {
                flag = 0;
                for (int j = 0; j < a[i]; j++)
                {
                    a[i + j + 1] -= 1;
                    if (a[i + j + 1] < 0) {
                        cout << "no" << endl;
                        flag = 1;
                        break;
                    }
                }
                if (flag) break;
                sort(a + i + 1, a + n, cmp);
            }
            if (a[n - 1] == 0 && flag == 0) cout << "yes" << endl;
        }
    }
    return 0;
}

更快點:

#include<bits/stdc++.h>
using namespace std;
int a[2005];
int n;
bool Slove()
{
    for (int i = 0; i < n; ++i)
    {
        sort(a + i, a + n, greater<int>());//非增序排列
        if (a[i] == 0)
            return true;
        if (i + a[i] >= n)               //不存在前a[i]大個數
            return false;
        for (int j = i + 1; j <= i + a[i]; ++j)//前a[i]的數大-1
        {
            a[j]--;
            if (a[j] < 0)
                return false;
        }
    }
}


int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d", &n);
        int sum = 0;
        for (int i = 0; i < n; i++)
        {
            scanf("%d", &a[i]);
            sum += a[i];
        }

        if (sum % 2)
        {
            puts("no");
            continue;
        }

        if (Slove())
            puts("yes");
        else
            puts("no");
    }
}