ZOJ - 3732 Graph Reconstruction (Havel_Hakimi定理 )

Graph Reconstruction

 题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3732

Let there be a simple graph with N vertices but we just know the degree of each vertex. Is it possible to reconstruct the graph only by these information?

A simple graph is an undirected graph that has no loops (edges connected at both ends to the same vertex) and no more than one edge between any two different vertices. The degree of a vertex is the number of edges that connect to it.

Input

There are multiple cases. Each case contains two lines. The first line contains one integer N (2 ≤ N ≤ 100), the number of vertices in the graph. The second line conrains N integers in which the i th item is the degree of i th vertex and each degree is between 0 and N-1(inclusive).

Output

If the graph can be uniquely determined by the vertex degree information, output "UNIQUE" in the first line. Then output the graph.

If there are two or more different graphs can induce the same degree for all vertices, output "MULTIPLE" in the first line. Then output two different graphs in the following lines to proof.

If the vertex degree sequence cannot deduced any graph, just output "IMPOSSIBLE".

The output format of graph is as follows:

N E
u1 u2 ... uE
v1 v2 ... vE

Where N is the number of vertices and E is the number of edges, and {u i,v i} is the i th edge the the graph. The order of edges and the order of vertices in the edge representation is not important since we would use special judge to verify your answer. The number of each vertex is labeled from 1 to N. See sample output for more detail.

Sample Input

1
0
6
5 5 5 4 4 3
6
5 4 4 4 4 3
6
3 4 3 1 2 0

Sample Output

UNIQUE
1 0


UNIQUE
6 13
3 3 3 3 3 2 2 2 2 1 1 1 5
2 1 5 4 6 1 5 4 6 5 4 6 4
MULTIPLE
6 12
1 1 1 1 1 5 5 5 6 6 2 2
5 4 3 2 6 4 3 2 4 3 4 3
6 12
1 1 1 1 1 5 5 5 6 6 3 3
5 4 3 2 6 4 3 2 4 2 4 2
IMPOSSIBLE

题目大意:无向图有n个节点,给出每个点的度,判断这个无向图,若不存在输出: IMPOSSIBLE,若存在唯一的一个输出:UNIQUE ,图的节点数,边数,和边的信息,若存在多个符合的无向图输出:MULTIPLE  并输出其中的两个图的情况

思路:

首先要知道Havel_Hakimi定理,这是判断一个序列是否可图化的定理,下面简单介绍一下这个定理:

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

过程:1.对序列递减排序:d1>=d2>=d3....>=dn

2.删除d1 ,并对后面的d1个点的度-1 (相当于把度最大的这个点与后面d1个点相连,所以后面d1个点的度都减一,然后这个点的边已经连完了就不用管这个点了,d1 是度最大这个点的度数)

对以上操作进行n-1次,如果在操作的过程中出现点的度为负数,则说明不可图化,如果没有出现负度,n-1次操作后应该还剩下一个的没有删掉,即还剩下点n,如果dn==0则可图化,否则不可图化。

核心代码:

bool Havel_Hakimi()
{
    for(int i=0;i<n-1;i++)
    {
        sort(e+i,e+n,cmp); //把点按度数从大到小排序
        if(i+e[i].d>=n) return 0;  //如果这一点的度大于剩下的点,则不可图化
        for(int j=i+1;j<=i+e[i].d;j++) //把后面的度数个点的度-1
        {
            e[j].d--;
            if(e[j].d<0) return 0; //如果度下与0,不可图化
        }
    }
    if(e[n-1].d!=0) return 0;
    return 1;
}

这道题还要考虑图是否唯一,判断是否成图方式唯一的方法是在每个点寻找连接的边的时候,找到的最后一个点,如果与它之后第一个度点的度是相同的且度不为0,则两个点可以交换位置并且交换后依然可图化,而出现至少两种建图方式。

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=105;
struct node
{
    int d,id;
} e[N],e1[N]; //存点
int n,tot;
pair<int,int>p1[N*N],p2[N*N]; //存图的边
bool cmp(node a,node b)  //按度从大到小排序
{
    if(a.d==b.d) return a.id>b.id;  
    return a.d>b.d;
}
bool Havel_Hakimi()  //判断是否可图化
{
    tot=0;
    for(int i=0;i<n-1;i++)
    {
        sort(e+i,e+n,cmp);
        if(i+e[i].d>=n) return 0;
        for(int j=i+1;j<=i+e[i].d;j++)
        {
            p1[tot++]=make_pair(e[i].id,e[j].id); //记录边
            e[j].d--;
            if(e[j].d<0) return 0;
        }
    }
    if(e[n-1].d!=0) return 0;
    return 1;
} 
bool fun() //判断是否有其他成图方式
{
    int flag=0;
    int tot1=0;
    for(int i=0;i<n-1;i++)
    {
        sort(e1+i,e1+n,cmp);
        int tmp=e1[i].d+i; 
        if(tmp<n-1&&e1[tmp].d==e1[tmp+1].d&&e1[tmp].d!=0)
        {
            flag=1;
            swap(e1[tmp].id,e1[tmp+1].id);
        }
        for(int j=i+1;j<=tmp;j++)
            {
                p2[tot1++]=make_pair(e1[i].id,e1[j].id);
                e1[j].d--;
            }
    }
    return flag;
}
int main()
{
    while(~scanf("%d",&n))
    {
        int sum=0;
        for(int i=0; i<n; i++)
        {
            scanf("%d",&e[i].d);
            e1[i].id=e[i].id=i+1;
            e1[i].d=e[i].d;
            sum+=e[i].d;
        }
        if(sum%2) printf("IMPOSSIBLE\n"); //如果度数和为奇数一定不能成图,一条边连两个点
        else
        {
            if(!Havel_Hakimi()) printf("IMPOSSIBLE\n"); //不可图化
            else
            {
                if(fun()) //可图化且图不唯一,输出两个图的信息
                {
                    printf("MULTIPLE\n");
                    printf("%d %d\n",n,tot);
                    for(int i=0;i<tot;i++) 
                        printf("%d%c",p1[i].first,i==tot-1?'\n':' ');
                    for(int i=0;i<tot;i++)
                        printf("%d%c",p1[i].second,i==tot-1?'\n':' ');
                    printf("%d %d\n",n,tot);
                    for(int i=0;i<tot;i++)
                        printf("%d%c",p2[i].first,i==tot-1?'\n':' ');
                    for(int i=0;i<tot;i++)
                        printf("%d%c",p2[i].second,i==tot-1?'\n':' ');
                }
                else //图唯一
                {
                    printf("UNIQUE\n");
                    printf("%d %d\n",n,tot);
                    for(int i=0;i<tot;i++)
                        printf("%d%c",p1[i].first,i==tot-1?'\n':' ');
                    for(int i=0;i<tot;i++)
                        printf("%d%c",p1[i].second,i==tot-1?'\n':' ');
                    if(tot==0) printf("\n\n"); //特判图只有一个节点没有边,要输出两个换行
                }
            }
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值