计蒜客画图游戏(Havel-Hakimi定理)

问题描述

蒜头君想让你帮他画一个无向图,图中有 n 个顶点,蒜头告诉你这 n 个顶点的度数。为了简化问题,你只需要告诉蒜头君图的邻接矩阵就可以了,图中不存在自环的情况,也就是说邻接矩阵的正对角线均为 0。(矩阵可能不唯一,只要符合要求即可)

输入格式 

第一行输入一个整数 n,代表顶点的个数(1≤n≤15),第二行是 n 个整数,分别代表这 n 个顶点的度数。

输出格式 

输出一个 n×n 的 01 矩阵,代表图的邻接矩阵。如果没有符合要求的图,则输出“None”。  本题答案不唯一,符合要求的答案均正确。

样例输入1

4

2 3 2 1

样例输出1  

0 1 1 0 

1 0 1 1

1 1 0 0

0 1 0 0 

样例输入2 

3 2 1 1 

样例输出2  

None

思路:

关于Havel-Hakimi定理请自行上网寻找。

利用结构体来记录每个节点的编号和度。我们将节点按度数排序,每个节点的度为a[i]。套用公式,对于度数最大的那个点,我们将其与度数次大的a[i]个点用边连起来(即公式中将次大的a[i]个点的度值减一),然后这个点就可以不管了(即公式中删除最大的点)。这样一直做,如果出现有边的度数为负,则这个序列不可图,输出None,若一直减少到所有点度数为0,则得到一个可行的图。

细节:

1、由于只有部分点的度减一,顺序可能会有所不同,每次都应该重新排序。

2、可能会出现度数超过节点数量的情况,也要考虑。

代码:

#include
using namespace std;
const int N=20;
int n,l,cur,ma[N][N];
struct Node{
	int num,v;
} node[N];
struct cmp{
	bool operator()(const Node &a,const Node &b){
		return a.v>b.v;
	}
};
bool check(){
	for(int i=1;i<=n;i++)
		if(node[i].v>=n||node[i].v<0) return false;
	return true;
}
int main(){
	freopen("data.in","r",stdin);
	scanf("%d",&l); n=l;
	for(int i=1;i<=n;i++){
		scanf("%d",&node[i].v);
		node[i].num=i;
	}
	sort(node+1,node+n+1,cmp());
	while(n){
		cur=0;
		if(!check()){
			printf("None"); return 0;
		}//判断当前情况是否合法
		for(int i=2;i-1<=node[1].v;i++){
			node[i].v--;
			if(!node[i].v) cur++;//用cur记录在连边时度变成0的节点个数 
			ma[node[1].num][node[i].num]=ma[node[i].num][node[1].num]=1;
		}
		node[1].v=0; 
		sort(node+1,node+n+1,cmp());//先排序再减少长度,因为有些有度的节点在后面 
		n-=1+cur;
	}
	for(int i=1;i<=l;i++){
		for(int j=1;j<=l;j++)
			printf("%d ",ma[i][j]);
		printf("\n");
	}
	return 0;
}


你可能感兴趣的:(计蒜客画图游戏(Havel-Hakimi定理))