ZOJ 3732 可图性判定--Havel-Hakimi定理

7 篇文章 0 订阅

题意:给定n个点度数,问是否可以构造一个简单图。

思路:Havel-Hakimi定理 :

1.将度数从小到大排序

2.用第一个向后面连续d[1]个点连边,若点数不够则不能构造

3.若点数够,则将每个点度数减1,若出现负值,则不能构造,

4.去掉该点返回步骤一,直到集合中没有点。

对于多个图,只需要判定i+d[i]和i+d[i]+1这两个点度数是否一致,

若一致就交换。即可达到不同图的目标。

#include<bits/stdc++.h>
#define fir first
#define sec second
using namespace std;
const int N=110;
int deg[N];
int n;
vector<int> u[2], v[2];

bool havel(){
    int tmp[N];
    for(int i=1; i<=n; i++)
        tmp[i]=deg[i];
    for(int i=1; i<n; i++){
        sort(tmp+i, tmp+1+n, greater<int>());
        if(tmp[i] > n-i) return false;
        for(int j=1; j<=tmp[i]; j++){
            tmp[i+j]--;
            if(tmp[i+j]<0) return false;
        }
    }
    return true;
}

bool cmp(pair<int, int> a, pair<int, int> b){
    return a.fir>b.fir;
}

bool solve(){
    pair<int,int> p[N];
    for(int i=1; i<=n; i++)
        p[i].fir=deg[i], p[i].sec=i;
    bool ok=false;
    for(int i=1; i<=n; i++){
        sort(p+i, p+1+n, cmp);

        if(i+p[i].fir<n && p[i+p[i].fir].fir==p[i+p[i].fir+1].fir && p[i+p[i].fir].fir!=0){
            ok=true;
        }
        for(int j=1; j<=p[i].fir; j++){
            u[0].push_back(p[i].sec);
            v[0].push_back(p[i+j].sec);
            p[i+j].fir--;
        }

    }

    if(!ok) return true;

    for(int i=1; i<=n; i++)
        p[i].fir=deg[i], p[i].sec=i;

    for(int i=1; i<=n; i++){
        sort(p+i, p+1+n, cmp);

        if(i+p[i].fir<n && p[i+p[i].fir].fir==p[i+p[i].fir+1].fir && p[i+p[i].fir].fir!=0){
            swap(p[i+p[i].fir].sec, p[i+p[i].fir+1].sec);
        }

        for(int j=1; j<=p[i].fir; j++){
            u[1].push_back(p[i].sec);
            v[1].push_back(p[i+j].sec);
            p[i+j].fir--;
        }

    }

    return false;
}

int main(){
    while(~scanf("%d", &n)){
        u[0].clear(); u[1].clear();
        v[0].clear(); v[1].clear();
        for(int i=1; i<=n; i++)
            scanf("%d", deg+i);

        if(!havel()){
            printf("IMPOSSIBLE\n");
        }
        else{

                if(solve()){
                    printf("UNIQUE\n");
                    printf("%d %d\n", n, u[0].size());
                    if(u[0].size()) printf("%d", u[0][0]);
                    for(int i=1; i<u[0].size(); i++)
                        printf(" %d", u[0][i]);
                    puts("");
                    if(v[0].size()) printf("%d", v[0][0]);
                    for(int i=1; i<v[0].size(); i++)
                        printf(" %d", v[0][i]);
                    puts("");
                }
                else{
                    printf("MULTIPLE\n");
                    printf("%d %d\n", n, u[0].size());
                    if(u[0].size()) printf("%d", u[0][0]);
                    for(int i=1; i<u[0].size(); i++)
                        printf(" %d", u[0][i]);
                    puts("");
                    if(v[0].size()) printf("%d", v[0][0]);
                    for(int i=1; i<v[0].size(); i++)
                        printf(" %d", v[0][i]);
                    puts("");

                    printf("%d %d\n", n, u[1].size());
                    if(u[1].size()) printf("%d", u[1][0]);
                    for(int i=1; i<u[1].size(); i++)
                        printf(" %d", u[1][i]);
                    puts("");
                    if(v[1].size()) printf("%d", v[1][0]);
                    for(int i=1; i<v[1].size(); i++)
                        printf(" %d", v[1][i]);
                    puts("");
                    }

            }

    }

    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值