可图性判定HavelHakimi定理

两个概念

1、度序列

  若把图G所有顶点的度数排成一个序列S,则称S为图G的度序列。

2、序列是可图的

  一个非负整数组成的序列如果是某个无向图的度序列,则称该序列是可图的。


Havel-Hakimi定理

由非负整数组成的非增序列S:d1, d2 ,..., dn (n≥2,d1≥1)是可图的,当且仅当序列S1:d2-1,d3-1,...,dd1+1-1,dd1+2,...,dn是可图的。其中,序列S1中有n-1个非负整数,S序列中d1后的前d1个度数(即d2~dd1+1)减1后构成S1中的前d1个数。


应用:POJ 1659 Frogs' Neighborhood

http://poj.org/problem?id=1659

贴上一个博客

http://blog.csdn.net/monkey_little/article/details/6358601

对于该题目中的第一个序列,分析如下:

具体操作时候,每次都把排序好的序列第一个元素处理完以后就置为0,加入到队列的最后。若是最后元素全为0,则该序列是可图的。若在中间出现某个元素减一之后变为负的,则说明此序列是不可图的。

我的AC代码如下:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #define MAXN 10
 5 typedef struct Company
 6 {
 7   int data;
 8   int no;
 9 }Company;
10 Company x[MAXN];
11 int map[MAXN][MAXN];
12 int Compare(const void *elem1, const void *elem2)
13 {
14   Company *p1 = (Company*)elem1;
15   Company *p2 = (Company*)elem2;
16 //  if (p1->data == p2->data)
17 //  {
18 //    return p1->no - p2->no;
19 //  }
20   return p2->data - p1->data;
21 }
22 int main()
23 {
24   int T, N;
25   scanf("%d", &T);
26   while(T--)
27   {
28     scanf("%d", &N);
29     memset(map, 0, sizeof(map));
30     int flag = 0;
31     for (int i = 0; i < N; ++i)
32     {
33       scanf("%d", &x[i].data);
34       x[i].no = i;
35     }
36     qsort(x, N, sizeof(Company), Compare);
37     while(!flag && x[0].data)
38     {
39       int start = x[0].data;
40       for (int i = 1; i < start+1; ++i)
41       {
42         x[i].data--;
43         if (x[i].data < 0)
44         {
45           flag = 1;
46           break;
47         }
48         map[x[0].no][x[i].no] = 1;
49         map[x[i].no][x[0].no] = 1;
50       }
51       x[0].data = 0;
52       qsort(x, N, sizeof(Company), Compare);
53     }
54     if (flag)
55     {
56       printf("NO\n");
57     }else
58     {
59       printf("YES\n");
60       for (int i = 0; i < N; ++i)
61       {
62         for (int j = 0; j < N; ++j)
63         {
64           printf(j == 0 ? "%d" : " %d", map[i][j]);
65         }
66         printf("\n");
67       }
68     }
69     if (T)
70     {
71       printf("\n");
72     }
73   }
74   return 0;
75 }

x.no这个属性用来记录每个输入数据的输入时的编号次序,以用来在map[][]数组填充1时用,否则不知道该x[?][?] = 1;

flag是一个标志位,若中间有负数出现,就改变其值

思路源自以下代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 struct node
 6 {
 7     int num,e;
 8 }x[15];
 9 bool map[15][15];
10 int cmp(node a,node b)
11 {
12     if(a.num==b.num)
13         return a.e<b.e;
14     return a.num>b.num;
15 }
16 int judge(int n)
17 {
18     int i,num,tmp;
19     while(1){
20         sort(x+1,x+n+1,cmp);
21         if(!x[1].num)
22             return 1;//数组全为 0 的情况退出
23         for(i=2;i<=x[1].num+1;i++){
24             if(x[i].num>0){
25                 x[i].num--;
26                 map[x[1].e][x[i].e]=map[x[i].e][x[1].e]=1;
27             }
28             else
29                 return 0;
30         }
31         x[1].num=0;
32     }
33 }
34 int main()
35 {
36     int n,t,i,j;
37     bool flag;
38     scanf("%d",&t);
39     while(t--){ 
40         scanf("%d",&n);
41         for(i=1;i<=n;i++){
42             scanf("%d",&x[i].num);
43             x[i].e=i;
44         }
45         memset(map,0,sizeof(map));
46         flag=judge(n);
47 
48         if(flag){
49             printf("YES/n");
50             for(i=1;i<=n;i++){
51                 for(j=1;j<=n;j++)
52                     printf(j==1?"%d":" %d",map[i][j]);
53                 printf("/n");
54             }
55         }
56         else
57             printf("NO/n");
58         if(t)
59             printf("/n");
60     }
61     return 0;
62 }
View Code
原文地址:https://www.cnblogs.com/grubbyskyer/p/3849587.html