图论专题训练1-M(简单图的判定+构造,Havel定理)

 图论(一)度序列与Havel-Hakimi定理
2012-05-31 17:12:11
原创作品,允许转载,转载时请务必以超链接形式标明文章  原始出处 、作者信息和本声明。否则将追究法律责任。 http://sbp810050504.blog.51cto.com/2799422/883904

 

       我一直想写一些关于图论学习的收获。一直由于这样或者那样的原因都没有开始。无论如何,现在开始吧!
那么到底什么是图呢?我们这里说的图当然不是像照片一样的东东。最权威的定义:图=顶点集合+边集合。换言之,凡是能抽象成点集合和边集合的东西都是图。比如:中国地图。地图上的城市是一个个的点,而任意两个相邻城市之间有路。那么地图就是很直观的一种图。为了更方便的表示,我们引入了英语单词。Vertext(顶点),Edge(边),Graph(图)。不管什么图,就可以用G<V,E>表示了。
        地图是一种图,中国的七大水系网也是一种图。很多湖泊可以视为点,而长江、黄河这些可以看作边。由于水流基本上是单向的(当然也有倒流的情况,这里我们理想化就忽略了),所以,像这样:边有方向的图我们称为有方向的图(长江水只能从喜马拉雅流向东海,而绝对不会反过来的)简称有向图。如果边没有方向,那当然称为无向图了。
        我们还是回到地图。都说条条大路通北京(你说罗马也没错),那么有到底有多少条路到北京呢?在图论里,把这样连接到一个点的边的数量(比如连接到北京的路)称为:度!
对于图的所有顶点,我们可以统计出每个顶点的度。像这样的一串数字,我们称之为:度序列。那么反过来,给定一个序列,能否判断这个序列是可图的呢?这里有一个定理:Havel-Hakimi定理可以用来判定一个序列是否可图。Poj1659就是用Havel-Hakimi解决的。
    

  

Havel-Hakimi定理的内容可百度之。
Havel-Hakimi定理很容易理解:
三步走就可以了:
比如序列:4 7 7 3 3 3 2 1

下标
1
2
3
4
5
6
7
8
4
7
7
3
3
3
2
1

 
第一步:把序列按降序排序。

下标
1
2
3
4
5
6
7
8
7
7
4
3
3
3
2
1

 
第二步:删除第一个数7。序列变成

下标
1
2
3
4
5
6
7
7
4
3
3
3
2
1

 
第三步:从头开始,数7个数,也就是下标:[1,7]把[1,7]区间里的值都减1
由于第一个数已经删除,那么序列变成这样的了:

下标
1
2
3
4
5
6
7
6
3
2
2
2
1
0

然后:
重复第一步:排序。
重复第二步:删除第一个数6
重复第三步:从头开始数6个数:也就是下标【1,6】,把区间【1,6】中的数删除。序列变成:

下标
1
2
3
4
5
6
2
1
1
1
0
-1

由于已经出现了-1,而一个点的边数(度)不可能为负数。所以,我们就可以判定序列无法构成一个图,所以此序列是不可图的。
下面再举一个例子:
已经排序:

5
4
3
3
2
2
2
1
1
1.

删除第一个数5:

4
3
3
2
2
2
1
1
1.

 
把前面5个数减1:

3
2
2
1
1
2
1
1
1.

排序:

3
2
2
2
1
1
1
1
1.

删除第一个数3:
 

2
2
2
1
1
1
1
1.

把前面3个数减1:

1
1
1
1
1
1
1
1.

排序:

1
1
1
1
1
1
1
1.

删除第一个数1:

1
1
1
1
1
1
1.

把前面1个数减1:

0
1
1
1
1
1
1.

排序:

1
1
1
1
1
1
0

删除第一个数1:

1
1
1
1
1
0

把前面1个数减1:

0
1
1
1
1
0

排序:

1
1
1
1
0
0

              
依此类推:到最后只剩下:

0
0
0
0

由此判断该序列是可图的。


图论专题训练1-M(简单图的判定+构造,Havel定理)

分类: 算法题解-图论 算法题解-图论-图的连通性   112人阅读  评论(0)  收藏  举报

题目链接

  1. /* 
  2.  *题目大意: 
  3.  *给出一个图的每个点的度的序列,求能否构成一个简单图,如果能构出简单图,则输出图的邻接矩阵; 
  4.  * 
  5.  *算法思想: 
  6.  *Havel定理的应用; 
  7.  *给定一个非负整数序列{dn},若存在一个无向图使得图中各点的度与此序列一一对应,则称此序列可图化; 
  8.  *若图为简单图,则称此序列可简单图化; 
  9.  * 
  10.  *可图化的判定: 
  11.  *d1+d2+……dn==0(mod 2); 
  12.  * 
  13.  *处理过程: 
  14.  *每次处理度数最大的点,设其度数为d则将他与度数最大的d个点(不含自己)个连一条边(若该点度数大于0),更新度数; 
  15.  *重复上面操作,如果最后恰好所有度数为0则为可行方案; 
  16. **/  
  17.   
  18. #include<iostream>  
  19. #include<cstdio>  
  20. #include<cstdlib>  
  21. #include<algorithm>  
  22. #include<cstring>  
  23. using namespace std;  
  24.   
  25. const int N=20;  
  26. int map[N][N];  
  27. int n;  
  28.   
  29. struct node  
  30. {  
  31.     int degree;  
  32.     int id;  
  33. } a[N];  
  34.   
  35. bool cmp(node x , node y)  
  36. {  
  37.     return x.degree>y.degree;  
  38. }  
  39.   
  40. int main()  
  41. {  
  42.     //freopen("C:\\Users\\Administrator\\Desktop\\kd.txt","r",stdin);  
  43.     int t1;  
  44.     scanf("%d",&t1);  
  45.     int t2=0;  
  46.     while(t1--)  
  47.     {  
  48.         if(t2)  
  49.         puts("");  
  50.         t2++;  
  51.         memset(map,0,sizeof(map));  
  52.         scanf("%d",&n);  
  53.         int sum=0;  
  54.         for(int i=0; i<n; i++)  
  55.         {  
  56.             scanf("%d",&a[i].degree);  
  57.             a[i].id=i;  
  58.             sum+=a[i].degree;  
  59.         }  
  60.         if(sum%2)  
  61.         {  
  62.             puts("NO");  
  63.             continue;  
  64.         }  
  65.   
  66.         int flag=0;  
  67.         for(int i=0; i<n; i++)  
  68.         {  
  69.             sort(a,a+n,cmp);  
  70.             if(a[0].degree==0)  
  71.             {  
  72.                 flag=1;  
  73.                 break;  
  74.             }  
  75.             for(int j=0; j<a[0].degree; j++)  
  76.             {  
  77.                 a[j+1].degree--;  
  78.                 int x=a[0].id;  
  79.                 int y=a[j+1].id;  
  80.                 map[x][y]=map[y][x]=1;  
  81.                 if(a[j+1].degree<0)  
  82.                 {  
  83.                     flag=2;  
  84.                     break;  
  85.                 }  
  86.             }  
  87.             a[0].degree=0;  
  88.             if(flag==2)  
  89.                 break;  
  90.         }  
  91.         if(flag==1)  
  92.         {  
  93.             puts("YES");  
  94.             for(int i=0; i<n; i++)  
  95.             {  
  96.                 int j=0;  
  97.                 for(; j<n-1; j++)  
  98.                     printf("%d ",map[i][j]);  
  99.                 printf("%d\n",map[i][j]);  
  100.             }  
  101.         }  
  102.         else  
  103.             puts("NO");  
  104.     }  
  105.     return 0;  
  106. }  

Havel-Hakimi定理

分类: 学习篇   662人阅读  评论(0)  收藏  举报

1,Havel-Hakimi定理主要用来判定一个给定的序列是否是可图的。

2,首先介绍一下度序列:若把图 G 所有顶点的度数排成一个序列 S,则称 S 为图 G 的度序列。

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

4,判定过程:(1)对当前数列排序,使其呈递减,(2)从S【2】开始对其后S【1】个数字-1,(3)一直循环直到当前序列出现负数(即不是可图的情况)或者当前序列全为0 (可图)时退出。

5,举例:序列S:7,7,4,3,3,3,2,1  删除序列S的首项 7 ,对其后的7项每项减1,得到:6,3,2,2,2,1,0,继续删除序列的首项6,对其后的6项每项减1,得到:2,1,1,1,0,-1,到这一步出现了负数,因此该序列是不可图的。

6,应用:http://poj.org/problem?id=1659

题意很简单,分析之后会发现其实本题的意思就是想问:给定一个非负数序列,问是不是一个可图的序列,即能不能根据这个序列构造一个图,有2种不合理的情况:(1)某次对剩下序列排序后,最大的度数(设为d1)超过了剩下的顶点数;(2)对最大度数后面的d1个数各减1后,出现了负数。

贴下代码:

[c-sharp]  view plain copy
  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. }  

 



  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值