POJ1659 Frogs' Neighborhood(Havel定理)

题目:

Frogs' Neighborhood
Time Limit: 5000MS Memory Limit: 10000K
Total Submissions: 9932 Accepted: 4152 Special Judge

Description

未名湖附近共有N个大小湖泊L1L2, ..., Ln(其中包括未名湖),每个湖泊Li里住着一只青蛙Fi(1 ≤ i ≤ N)。如果湖泊LiLj之间有水路相连,则青蛙FiFj互称为邻居。现在已知每只青蛙的邻居数目x1x2, ..., xn,请你给出每两个湖泊之间的相连关系。

Input

第一行是测试数据的组数T(0 ≤ T ≤ 20)。每组数据包括两行,第一行是整数N(2 < N < 10),第二行是N个整数,x1x2,..., 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 

Source

[Submit]   [Go Back]   [Status]   [Discuss]

思路:

这个是Havel定理的应用,关于Havel定理:Havel-Hakimi定理(判断一个序列是否可图)


首先我们对这个序列进行排序,然后找出最大的度数n,然后在这个排好序的序列中对接下来的n个数进行减一,如果出现两种情况就证明这个序列不可图,否则就就在邻接矩阵中把这两个点连起来

①某次对剩下的序列排序后,最大的度数超过了剩下的顶点数

②对最大的度数后面的n个度数进行减1后,出现了负数

如果出现了这两种情况,那么这个序列不可图


我们用一个结构体来记录一个顶点的度数和这个顶点的标号,具体看代码


代码:

#include <cstdio>
#include <cstring>
#include <string>
#include <set>
#include <iostream>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 10000007
#define debug() puts("what the fuck!!!")
#define N (1010000)
#define ll long long
using namespace std;
struct node
{
	int degree,id;//顶点的度数和标号
} v[20];
int map[20][20];
bool cmp(node a,node b)
{
	return a.degree>b.degree;
}
int main()
{
	int t,n,flag;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i=0; i<n; i++)
		{
			scanf("%d",&v[i].degree);
			v[i].id=i;//记录顶点的编号
		}
		mem(map,0);
		flag=1;
		for(int k=0; k<n; k++)
		{
			sort(v+k,v+n,cmp);//从第k位开始,对整个数组排序
			int i=v[k].id;//当前要连的顶点的编号
			int d1=v[k].degree;//记录当前这个节点的度数
			if(d1>n-k-1)//当当前节点的度数比剩余的顶点数要大的时候,则不存在相连的关系
				flag=0;
			for(int r=1; r<=d1&&flag; r++)//从当前点开始给后面的度数减一
			{
				int j=v[k+r].id;//当前要连的顶点的编号
				if(v[k+r].degree<=0)//出现负值代表不存在相连的关系
					flag=0;
				v[k+r].degree--;
				map[i][j]=map[j][i]=1;
			}
		}
		if(flag)
		{
			puts("YES");
			for(int i=0; i<n; i++)
			{
				for(int j=0; j<n; j++)
				{
					if(j)printf(" ");
					printf("%d",map[i][j]);
				}
				puts("");
			}
		}
		else
			puts("NO");
		if(t)
			puts("");
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值