Havel 定理:
序列的可图:给出一个 由非负整数组成的序列,如果是某个无向图的度序列,则称该序列是可图的。
而 Havel 定理,就是判断序列的可图的方法。先按度数从大到小排序, 每次处理完度数一个点,删除之,
剩下的排序。再处理度数最大的点。 如果出现不合理的情况,则该序列不可图。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MaxN = 18;
int T, n;
int graph[MaxN][MaxN]; //邻接矩阵
int flag; //存在合理的邻接关系
struct Vertex
{
int degree;
int index;
}v[MaxN];
bool cmp(Vertex a, Vertex b)
{
return a.degree > b.degree;
}
void solve()
{
memset(graph, 0, sizeof(graph));
flag = 1;
int i, j, d1; // d1 是 对剩下序列排序后,第1个顶点的度数
for(int k = 0; k < n && flag; ++k)
{
//对 v 数组后 n - k 个元素按非递增顺序排序
sort(v + k, v + n, cmp);
i = v[k].index; //第k个顶点的序号
d1 = v[k].degree;
if(d1 > n - k - 1)
flag = 0;
for(int r = 1; r <= d1 && flag; ++r)
{
j = v[k + r].index;
if(v[k + r].degree <= 0)
flag = 0;
v[k + r].degree--;
graph[i][j] = graph[j][i] = 1;
}
}
if(flag)
{
printf("YES\n");
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
if(j)
printf(" ");
printf("%d", graph[i][j]);
}
printf("\n");
}
}else{
printf("NO\n");
}
printf("\n");
}
int main()
{
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
for(int i = 0; i < n; ++i)
{
scanf("%d", &v[i].degree);
v[i].index = i;
}
solve();
}
return 0;
}
/*
3
7
4 3 1 5 4 2 1
6
4 3 1 4 2 0
6
2 3 1 1 2 1
*/
/*
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
*/