先行概念:
度序列(degree sequence):若把图 G所有顶点的度数排成一个序列 s,则称 s为图 G的度序 列。例如,图 1.1(a)所示无向图 G1的度序列为 s: 2, 5, 4, 3, 3, 1;或 s': 1, 2, 3, 3, 4, 5;或 s'': 5, 4, 3, 3, 2, 1。 其中序列 s 是按顶点序号排序的,序列 s'是按度数非减顺序排列的,序列 s''是按度数非增顺序排 列的。给定一个图,确定它的度序列很简单,但是其逆问题并不容易,即给定一个由非负整数组 成的有限序列 s,判断 s是否是某个图的度序列。 序列是可图的(graphic):一个非负整数组成的有限序列如果是某个无向图的度序列,则称 该序列是可图的。判定一个序列是否是可图的,有以下 Havel-Hakimi 定理。
引入正题
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个数。 例如,判断序列 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,到这一步出现了负数。由于图中不可能存在负度数的顶点,因此该序列不是可图的。 再举一个例子,判断序列 s: 5, 4, 3, 3, 2, 2, 2, 1, 1, 1 是否是可图的。删除序列 s的首项 5,对其 后的 5项每项减 1,得到:3, 2, 2, 1, 1, 2, 1, 1, 1,重新排序后为:3, 2, 2, 2, 1, 1, 1, 1, 1。继续删除序 列的首项 3,对其后的 3项每项减 1,得到:1, 1, 1, 1, 1, 1, 1, 1。如此再陆续得到序列:1, 1, 1, 1, 1, 1, 0;1, 1, 1, 1, 0, 0;1, 1, 0, 0, 0;0, 0, 0, 0。由此可判定该序列是可图的。 Havel-Hakimi 定理实际上给出了根据一个序列 s构造图(或判定 s不是可图的)的方法:把序 列s按照非增顺序排序以后,其顺序为 d1, d2, …, dn;度数大的顶点(设为 v1),将它与度数次大 的前 d1 个顶点之间连边,然后这个顶点就可以不管了,即在序列中删除首项 d1,并把后面的 d1 个度数减 1;再把剩下的序列重新按非增顺序排序,按照上述过程连边;…;直到建出完整的图, 或出现负度数等明显不合理的情况为止。 例如,对序列 s: 3, 3, 2, 2, 1, 1构造图,设度数从大到小的 6个顶点为 v1~v6。首先 v1与v2、 v3、 v4连一条边,如图 1.4(a)所示;剩下的序列为 2, 1, 1, 1, 1。如果后面 4个1对应顶点 v3、v4、v5、 v6,则应该在 v2与v3、v2与v4之间连边,后在 v5与v6之间连边,如图(b)所示。如果后面 4个1 对应顶点 v5、v6、v3、v4,则应该在 v2与 v5、v2与 v6之间连边,后在 v3与 v4之间连边,如图(c) 所示。可见,由同一个可图的序列构造出来的图不一定是唯一的。
简单的来说:
执行过程如下:
1.先对度序列从大到小排序
2.选取第一个顶点的度为d,并将第一个顶点排除序列
3.对2-2+d内的顶点的度都减一。
重复执行这一个过程
判断不可图的条件:
1.在减一的过程中出现了负数
2.当前选取得到的d大于剩余的顶点的个数
以上条件满足其一都是不可图的
这里给出一个题目(hdoj的)
练习题目:http://acm.hdu.edu.cn/showproblem.php?pid=2454
在此给出我的解决代码
#include <iostream> #include <algorithm> #include <cstdio> using namespace std; const int MAXN=1005; int seq[MAXN]; bool com(int a,int b) { return a>b; } int main() { int n; int m; cin>>n; while(n--) { cin>>m; int flag=1; for(int i=0;i<m;i++) { cin>>seq[i]; } for(int i=0;i<m;i++) { sort(seq+i,seq+m,com); int d=seq[i]; if(i+d>=m){ flag=0; break; } for(int j=i+1;j<=i+d;j++) { seq[j]--; if(seq[j]<0){ flag=0; break; } } if(!flag) break; } if(flag) cout<<"yes"<<endl; else cout<<"no"<<endl; } return 0; }