POJ 1659【Havel-Hakimi 定理】

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;再把剩下的序列重新按非增顺序排

序,按照上述过程连边;…;直到建出完整的图,或出现负度数等明显不合理的情况为止。


再回到本题:

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

Description

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

Input

第一行是测试数据的组数T(0 ≤ T ≤ 20)。每组数据包括两行,第一行是整数N(2 < N < 10),第二行是N个整数,x1, x2,..., xn(0 ≤ xiN)。

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\n");
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    printf("%d",e[i][j]);
                    if(j!=n)
                        printf(" ");
                }
                printf("\n");
            }
        }else
            printf("NO\n");
        printf("\n");
    }
    return 0;
}




posted @ 2018-05-21 20:35  神探小小狄  阅读(175)  评论(0编辑  收藏  举报
【推荐】 程序员网址大全  |  EF CodeFirst  |  百度地图.NET  |  MyNPOI  |  开源  |  我的皮肤  |  ASP.NET MVC4  |  前端提升   |  LINQ   |  WCF   |  EasyUI  | aaronyang 页脚html代码