相邻两组测试数据之间输出一个空行。
样例输入:
2
7
4 3 1 5 4 2 1
6
4 3 1 4 2 0
样例输出:
YES
0 1 1 1 1 0 0
1 0 0 1 1 0 0
1 0 0 0 0 0 0
1 1 0 0 1 1 1
1 1 0 1 0 1 0
0 0 0 1 1 0 0
0 0 0 1 0 0 0
NO
Havel - Hakimi 定理
由非负整数组成的非增序列 s: d 1 , d 2 , …, d n (n ≥ 2, d 1 ≥ 1)
是可图的,当且仅当序列
s 1 : d 2 – 1, d 3 – 1, …, d d1+1 – 1, d d1+2 , …, d n
是可图的。序列 s 1 中有 n-1 个非负整数,s 序列中 d 1 后的前 d 1 个度数(即 d 2 ~d d1+1 )减 1 后构成
s 1 中的前 d 1 个数。
例如,判断序列 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 按照非增顺序排序以后,其顺序为 d 1 , d 2 , …, d n ;度数最大的顶点(设为 v 1 ) ,将它与度数次大
的前 d 1 个顶点之间连边,然后这个顶点就可以不管了,即在序列中删除首项 d 1 ,并把后面的 d 1
个度数减 1;再把剩下的序列重新按非增顺序排序,按照上述过程连边;…;直到建出完整的图,
或出现负度数等明显不合理的情况为止。
例如, 对序列 s: 3, 3, 2, 2, 1, 1 构造图, 设度数从大到小的 6 个顶点为 v 1 ~v 6 。 首先 v 1 与v 2 、 v 3 、
v 4 连一条边,如图 (a);剩下的序列为 2, 1, 1, 1, 1。如果后面 4 个 1 对应顶点 v 3 、v 4 、v 5 、
v 6 ,则应该在 v 2 与 v 3 、v 2 与 v 4 之间连边,最后在 v 5 与v 6 之间连边,如图(b)。如果后面 4 个 1
对应顶点 v 5 、v 6 、v 3 、v 4 ,则应该在 v 2 与 v 5 、v 2 与 v 6 之间连边,最后在 v 3 与 v 4 之间连边,如图(c)
。可见,由同一个可图的序列构造出来的图不一定是唯一的。
#include<stdio.h> #include<stdlib.h> #include<string.h> #define N 15 struct vertex { int degree; int index; }v[N]; int cmp(const void *a,const void *b) { return ((vertex*)b)->degree-((vertex*)a)->degree; } int main() { int r,k,p,q; int i,j; int d1; int t,n; int Edge[N][N],flag; scanf("%d",&t); while(t--){ scanf("%d",&n); for(i=0;i<n;i++){ scanf("%d",&v[i].degree); v[i].index=i; } memset(Edge,0,sizeof(Edge)); flag=1; for(k=0;k<n&&flag;k++){ qsort(v+k,n-k,sizeof(vertex),cmp); i=v[k].index; d1=v[k].degree; if(d1>n-k-1) flag=0; for(r=1;r<=d1&&flag;r++){ j=v[k+r].index; if(v[k+r].degree<=0) flag=0; v[k+r].degree--; Edge[i][j]=Edge[j][i]=1; } } if(flag){ puts("YES"); for(p=0;p<n;p++){ for(q=0;q<n;q++){ if(q) printf(" "); printf("%d",Edge[p][q]); } puts(""); } } else puts("NO"); if(t) puts(""); } return 0; }