[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");
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值