Havel-Hakimi 定理:
一个非负整数组成的有限序列如果是某个无向图的序列,则称该序列是可图的。
例如,判断序列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;再把剩下的序列重新按非增顺序排
序,按照上述过程连边;…;直到建出完整的图,或出现负度数等明显不合理的情况为止。
再回到本题:
| Time Limit: 5000MS | Memory Limit: 10000K | |||
| Total Submissions: 10443 | Accepted: 4340 | Special Judge | ||
Description
未名湖附近共有N个大小湖泊L1, L2, ..., Ln(其中包括未名湖),每个湖泊Li里住着一只青蛙Fi(1 ≤ i ≤ N)。如果湖泊Li和Lj之间有水路相连,则青蛙Fi和Fj互称为邻居。现在已知每只青蛙的邻居数目x1, x2, ..., xn,请你给出每两个湖泊之间的相连关系。
Input
第一行是测试数据的组数T(0 ≤ T ≤ 20)。每组数据包括两行,第一行是整数N(2 < N < 10),第二行是N个整数,x1, x2,..., xn(0 ≤ xi ≤ N)。
Output
对输入的每组测试数据,如果不存在可能的相连关系,输出"NO"。否则输出"YES",并用N×N的矩阵表示湖泊间的相邻关系,即如果湖泊i与湖泊j之间有水路相连,则第i行的第j个数字为1,否则为0。每两个数字之间输出一个空格。如果存在多种可能,只需给出一种符合条件的情形。相邻两组测试数据之间输出一个空行。
Sample Input
3 7 4 3 1 5 4 2 1 6 4 3 1 4 2 0 6 2 3 1 1 2 1
Sample Output
YES 0 1 0 1 1 0 1 1 0 0 1 1 0 0 0 0 0 1 0 0 0 1 1 1 0 1 1 0 1 1 0 1 0 1 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 NO YES 0 1 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0
注意:由该定理得到的图是不唯一的。
题解:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#define INF
using namespace std;
const int maxn=105;
int t,n;
int e[maxn][maxn];
struct node{
int degree;//顶点的度数
int num;//顶点的编号
}a[maxn];
bool cmp(node a,node b){//度数由大到小排序
return a.degree>b.degree;
}
int main()
{
scanf("%d",&t);
while(t--){
memset(e,0,sizeof e);
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i].degree);
a[i].num=i+1;//顶点编号由1-n
}
int flag=1;//旗帜变量
for(int i=0;i<n;i++){
sort(a,a+n,cmp);
if(a[i].degree>n-i-1){//如果后序顶点的数量小于当前顶点的度数,则无法构成图
flag=0;
break;
}
for(int j=i+1;j<=a[i].degree+i&&j<n;j++){
a[j].degree--;
if(a[j].degree<0){
flag=0;
break;
}
e[a[i].num][a[j].num]=e[a[j].num][a[i].num]=1;//连边
}
}
if(flag){
printf("YES
");
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
printf("%d",e[i][j]);
if(j!=n)
printf(" ");
}
printf("
");
}
}else
printf("NO
");
printf("
");
}
return 0;
}