Graph---Algorithm---Havel定理(可图判定)

本文介绍如何利用Havel定理判断给定的顶点度序列是否能构成简单无向图,并通过两种不同的实现方式展示算法的具体步骤。该算法采用贪心策略,通过不断连接度数最大的顶点来构造图。

概念:

给出一个无向图的顶点度序列{dn},要求判断能否构造出一个简单无向图。


Havel定理:

基于贪心。

每次把顶点按度大小从大到小排序,取出度最大的点Vi,依次和度较大的那些顶点Vj连接,同时减去Vj的度。

连接完之后就不再考虑Vi了(排序的时候可以直接从du[k]开始排;把这一点的度置零,为零了应该也没有影响了吧,因为如果对零减直接就跳出循环了,可判定不能成图),剩下的点再次排序然后找度最大的去连接……这样就可以构造出一个可行解。


判断无解条件:

<1> 若某次选出的Vi的度比剩下的顶点还多,则无解;(注意不要数组越界)

<2> 若某次Vj的度减成了负数,则无解。


模版:(POJ1659 Frogs' Neighborhood)


(我不懂为什么我用puts(“ ”)会WA。。。)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=13;
int ans[maxn][maxn];
int t,n;
struct p
{
    int ind,dunum;
}du[maxn];

bool operator<(const p &a,const p &b){
    return a.dunum>b.dunum;
}

int main()
{
    //freopen("in","r",stdin);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        memset(du,0,sizeof(du));
        memset(ans,0,sizeof(ans));
        int i,j,k;
        for(i=0;i<n;i++)
        {
            scanf("%d",&du[i].dunum);
            du[i].ind=i;
        }
        sort(du,du+n);//printf("%d ",du[n-1].dunum);
        bool f=true;
        //for(i=0;i<n;i++)
        //printf("id = %d , dunum= %d\n",du[i].ind,du[i].dunum);

        for(k=0;k<n;k++)
        {
                sort(du+k,du+n);
                if(du[k].dunum>n-k-1)
                {
                    f=false;
                    break;
                }
                for(j=1;j<=du[k].dunum;j++)
                {
                    du[k+j].dunum--;
                    if(du[k+j].dunum<0)
                    {
                        f=false;
                        break;
                    }
                    ans[du[k].ind][du[k+j].ind]=1;
                    ans[du[k+j].ind][du[k].ind]=1;
                }
        }
          // for(i=0;i<n;i++)
           //printf("id = %d , dunum= %d\n",du[i].ind,du[i].dunum);puts("");

        if(f)
        {
            printf("YES\n");
            for(i=0;i<n;i++)
            {
                for(j=0;j<n;j++)
                {
                    printf("%d ",ans[i][j]);
                }
                printf("\n");
            }
        }
        else
        printf("NO\n");
        printf("\n");
    }
    return 0;
}




另一种写法:(自己写的)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=13;
int ans[maxn][maxn];
int t,n;
struct p
{
    int ind,dunum;
    bool operator < (const p &rhs) const{
      return dunum > rhs.dunum;
    }
}du[maxn];

int main()
{
    //freopen("in","r",stdin);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        memset(du,0,sizeof(du));
        memset(ans,0,sizeof(ans));
        int i,j;
        for(i=0;i<n;i++)
        {
            scanf("%d",&du[i].dunum);
            du[i].ind=i;
        }
        sort(du,du+n);//printf("%d ",du[n-1].dunum);
        bool f=true;
       // for(i=0;i<n;i++)
        //printf("id = %d , dunum= %d\n",du[i].ind,du[i].dunum);
        while(du[0].dunum>0&&f)
        {
            if(du[0].dunum<n)
            {
                for(i=1;i<=du[0].dunum;i++)
                {
                    du[i].dunum--;
                    if(du[i].dunum<0)
                    {
                        f=false;
                        break;
                    }
                   // cout<<i<<endl;
                    //printf("du[%d] . dunum= %d\n",i,du[i].dunum);
                    ans[du[0].ind][du[i].ind]=1;
                    ans[du[i].ind][du[0].ind]=1;
                }
            }
            else
            {
                f=false;
                break;
            }
            du[0].dunum=0;
            sort(du,du+n);
        //for(i=0;i<n;i++)
      //printf("id = %d , dunum= %d\n",du[i].ind,du[i].dunum);puts("");

        }
        if(du[n-1].dunum==0&&du[0].dunum==0&&f)
        {
            printf("YES\n");
            for(i=0;i<n;i++)
            {
                for(j=0;j<n;j++)
                {
                    printf("%d ",ans[i][j]);
                }
                printf("\n");
            }
        }
        else
        printf("NO\n");
        printf("\n");
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值