POJ--1659--Frogs' Neighborhood【Havel-Hakimi定理构图】

链接:http://poj.org/problem?id=1659

题意:有n个湖泊,如果湖泊A和湖泊B之间有水路连接,则称他们互为邻居,现给出n个湖泊的邻居个数,如果他们可以构成一个图则输出YES和邻接矩阵,否则输出NO


这道题实际是给一个序列,看序列是否是一个可图序列。可以根据Havel-Hakimi定理的方法来构图,并在构图中判断是否出现了以下两种不合理的情形:

(1)某次对剩下的序列排序后,最大的度数(设为d1)超过了剩下的顶点数。

(2)对最大度数后面的d1个度数各减1后,出现了负数。

以上两种情况一旦出现一个就可以判定该序列不可图。


接下来就是n次循环,每次按当前度数排序,d1为当前度数最大值,每次循环可以减去2*d1个度数,并且更新邻接矩阵


#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 810
#define eps 1e-7
#define INF 0x7FFFFFFF
#define long long ll;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

int edge[12][12];
struct node{
    int d,num;
}a[15];
bool cmp(node x,node y){
    if(x.d==y.d)    return x.num<y.num;
    return x.d>y.d;
}
int main(){
    int t,n,i;
    scanf("%d",&t);
    while(t--){
        memset(edge,0,sizeof(edge));
        int sum = 0;
        scanf("%d",&n);
        for(i=0;i<n;i++){
            scanf("%d",&a[i].d);
            a[i].num = i + 1;
            sum += a[i].d;
        }
        int flag;
        while(sum>0){
            flag = 0;
            sort(a,a+n,cmp);
            sum -= a[0].d;
            if(n-a[0].d-1<0){
                flag = 1;
                break;
            }
            for(i=1;i<=a[0].d;i++){
                if(a[i].d>0){
                    a[i].d--;
                    sum--;
                    edge[a[i].num][a[0].num] = edge[a[0].num][a[i].num] = 1;
                }
                else{
                    flag = 1;
                    break;
                }
            }
            if(flag)    break;
            a[0].d = 0;
        }
        if(flag)    puts("NO");
        else{
            puts("YES");
            for(i=1;i<=n;i++){
                for(int j=1;j<n;j++){
                    printf("%d ",edge[i][j]);
                }
                printf("%d\n",edge[i][n]);
            }
        }
        printf("\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值