ZOJ3732 Graph Reconstruction Havel-Hakimi定理

分析:

给定一个非负整数序列{dn},若存在一个无向图使得图中各点的度与此序列一一对应,则称此序列可图化。

进一步,若图为简单图,则称此序列可简单图化 (来自百度百科)

可简单图化的判定可以用Havel-Hakimi定理,然后简述 Havel-Hakimi定理

Havel-Hakimi定理的过程:

1,按度数排序。

2,选取度数最大的点,如果该点度数为0,结束,有解

3,每次选一个度数最大的点,然后将后面的点的度数依次减1,表示该顶点和相应的顶点有边相连,

   如果有点的度数减到负数,结束,无解。

4,重复进行步骤1

然后这个题不只是判定有没有解,还需要判断是否有多解

 “个人认为此题的难点在于多解时要输出两个。在Havel-Hakimi定理的构造过程中,如果把某两个点“互换”,那么就可以构造出多解的,

那么什么样的两个点才可以互换呢,比如我现在已经排完序,要减的度数序列一直到p,这时,如果p+1的点的度数和p是相同的,

那么p位置和p+1是可以"互换“的,连这两个点中的哪一个都不会影响结果。”(该段文字引用网上某大牛的想法)

所以通过判断p和p+1是否相等,就可以判断是否多解

#include<cstdio>
#include<cstring>
#include<queue>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
typedef long long LL;
const int N=1e2+5;
const int INF=0x3f3f3f3f;
int a[N],d[N],c[N],n;
bool cmp(int x,int y)
{
    return c[x]>c[y];
}
bool check()
{
    for(int i=1;i<=n;++i)c[i]=d[i];
    for(int i=1; i<=n; ++i)
    {
        sort(a+1,a+1+n,cmp);
        if(!c[a[1]])break;
        for(int j=2,cnt=1; j<=n&&cnt<=c[a[1]]; ++j,++cnt)
        {
            --c[a[j]];
            if(c[a[j]]<0)return 0;
        }
        c[a[1]]=0;
    }
    return 1;
}
struct Edge
{
    int u,v;
} x[N*N];
bool checkmul()
{
    for(int i=1; i<=n; ++i)c[i]=d[i];
    for(int i=1; i<=n; ++i)
    {
        sort(a+1,a+1+n,cmp);
        if(!c[a[1]])break;
        int k=c[a[1]]+2;
        if(k<=n&&c[a[k]]==c[a[k-1]])return 1;
        for(int j=2,cnt=1; j<=n&&cnt<=c[a[1]]; ++j,++cnt)
            --c[a[j]];
        c[a[1]]=0;
    }
    return 0;
}
void print()
{
    int tot=0;
    for(int i=1; i<=n; ++i)c[i]=d[i];
    for(int i=1; i<=n; ++i)
    {
        sort(a+1,a+1+n,cmp);
        if(!c[a[1]])break;
        for(int j=2,cnt=1; j<=n&&cnt<=c[a[1]]; ++j,++cnt)
        {
            --c[a[j]];
            ++tot;
            x[tot].u=a[1],x[tot].v=a[j];
        }
        c[a[1]]=0;
    }
    for(int i=1; i<=tot; ++i)
    {
        printf("%d",x[i].u);
        if(i<tot)printf(" ");
    }
    printf("
");
    for(int i=1; i<=tot; ++i)
    {
        printf("%d",x[i].v);
        if(i<tot)printf(" ");
    }
    printf("
");
}
int main()
{
    while(~scanf("%d",&n))
    {
        int sum=0;
        for(int i=1; i<=n; ++i)
        {
            scanf("%d",&d[i]);
            sum+=d[i];
            a[i]=i;
        }
        if(!check())
        {
            printf("IMPOSSIBLE
");
            continue;
        }
        if(checkmul())
        {
            printf("MULTIPLE
");
            printf("%d %d
",n,sum/2);
            print();
            printf("%d %d
",n,sum/2);
            for(int i=1; i<=n; ++i)c[i]=d[i];
            int tot=0;
            bool flag=1;
            for(int i=1; i<=n; ++i)
            {
                sort(a+1,a+1+n,cmp);
                if(!c[a[1]])break;
                if(flag)
                {
                    int k=c[a[1]]+2;
                    if(k<=n&&c[a[k]]==c[a[k-1]])
                        swap(a[k],a[k-1]),flag=0;
                }
                for(int j=2,cnt=1; j<=n&&cnt<=c[a[1]]; ++j,++cnt)
                {
                    --c[a[j]];
                    ++tot;
                    x[tot].u=a[1],x[tot].v=a[j];
                }
                c[a[1]]=0;
            }
            for(int i=1; i<=tot; ++i)
            {
                printf("%d",x[i].u);
                if(i<tot)printf(" ");
            }
            printf("
");
            for(int i=1; i<=tot; ++i)
            {
                printf("%d",x[i].v);
                if(i<tot)printf(" ");
            }
            printf("
");
        }
        else
        {
            printf("UNIQUE
");
            printf("%d %d
",n,sum/2);
            print();
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/shuguangzw/p/5326057.html