Havel-Hakimi定理问题

来源:互联网 发布:关于大数据的书 编辑:程序博客网 时间:2024/05/16 15:09

昨天模拟了一下13年长沙现场赛的题,刚开始不太好,第一题思维有点僵硬,做的有点慢。不过总共做了4题,还算不错,至少是稳铜了,何时能模拟到银呀!

第一个水题A是维护后缀最小值,不过要注意等于0的情况。

第二题J貌似是概率DP,ZY过得。

第三题C是几何,只要算出点到直线的距离再分类讨论一下即可。不过这里要注意直线根本不和那个圆相交的情况(往反方向走了)。

第四题K是搜索。关于魔方的搜索题。想来Y学长肯定很喜欢做的吧。这里是二阶魔方,它只需要有6种状态转移即可(因为,比如顺时针转第1面,和逆时针转与第1面相对的那一面是等价的,所以只需要6个面全部顺时针转即可)。所以可以有复杂度为O(6^7)。当然,还可以适当剪下枝,就是前一个状态第1面顺时针转了,当前状态,与第1面对应的那一面就不需要顺时针转了,因为那样的话就转化原来的状态了。最后是100ms过的。

现在补一下银牌题G。

当然,先补一下Havel-Hakimi定理。据说是离散数学里的知识,,好像没学过。。



Frogs’ Neighborhood

题目传送:POJ - 1659 - Frogs’ Neighborhood

分析:给出一个度序列,问这个序列是否可以构成图,而是否可以构成图根据
Havel-Hakimi定理的方法来构图

这个题还是在机房做的。。

以下为转载:

Havel-Hakimi定理:
1,一个非负整数组成的有限序列如果是某个无向图的度序列,则称该序列是可图的。

2,判定过程:
(1)对当前数列排序,使其呈非递增序列
(2)从第二个数开始对其后d[1]个数字减1,d[1]代表排序后第1个数的值
(3)然后删除第一个之后对剩下的数继续排序
(4)一直循环直到当前序列出现负数(即不是可图的情况)或者当前序列全为0 (可图)时退出。

3,举例:
序列S:7,7,4,3,3,3,2,1
删除序列S的首项 7 ,对其后的7项每项减1,
得到:6,3,2,2,2,1,0,
继续删除序列的首项6,
对其后的6项每项减1,
得到:2,1,1,1,0,-1,
到这一步出现了负数,因此该序列是不可图的

再举例:
序列:4 3 1 5 4 2 1
排序之后:5 4 4 3 2 1 1
删除5对后面5个数减1操作
3 3 2 1 0 1
排序
3 3 2 1 1 0
删除3对后面3个数减1操作
2 1 0 1 0
排序
2 1 1 0 0
删除2 对后面2个数减1操作
0 0 0 0
全为0,可图

AC代码:

#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>using namespace std;int n;struct node {    int id;    int x;    bool operator < (const node& a) const {        return x > a.x;    }}a[15];int mp[15][15];int main() {    int T;    scanf("%d", &T);    while(T --) {        memset(mp, 0, sizeof(mp));        scanf("%d", &n);        for(int i = 1; i <= n; i ++) {            scanf("%d", &a[i].x);            a[i].id = i;        }        int flag = 1;        while(1) {            sort(a + 1, a + n + 1);            if(a[1].x <= 0) break;            //for(int j = 1; j <= n;j ++) cout << a[j].id << " "; cout << endl;             for(int j = 2; j <= a[1].x + 1 && flag; j ++) {                mp[a[1].id][a[j].id] = 1;                mp[a[j].id][a[1].id] = 1;                a[j].x --;                if(a[j].x < 0) {                    flag = 0;                    break;                }            }            a[1].x = 0;        }        if(flag) {            printf("YES\n");            for(int i = 1; i <= n; i ++) {                for(int j = 1; j < n; j ++) {                    printf("%d ", mp[i][j]);                }                printf("%d\n", mp[i][n]);            }        }        else printf("NO\n");        if(T > 0) printf("\n");    }    return 0;}



Graph Reconstruction

题目传送:ZOJ - 3732 - Graph Reconstruction

13年长沙赛区银牌题。

分析:Havel-Hakimi定理

在了解Havel-Hakimi这个定理的基础上,花了40多分钟搞出来的,还算不错。不过得先知道这个定理。事实上这个定理就是贪心的过程。

其实这个题就是考得Havel-Hakimi定理。剩下的就很好办了,只需要考虑输出多解的情况就ok了。

为什么会有多解?因为有些边互换一下仍然可以构成图,且不影响度序列。

而只需要在Havel-Hakimi定理的过程中加一条判断即可,比如当前度数是5,要对后面5个度数都减去1,此时判断最后面一个度数和其后的一个度数是否相等,相等的话就说明可以交换,否则不行。

不过输出稍微有点复杂,因为是要输出一个类似关联矩阵的东西,这里为了方便,就用pair存了。

AC代码:

#include <map>#include <set>#include <list>#include <cmath>#include <deque>#include <queue>#include <stack>#include <bitset>#include <cctype>#include <cstdio>#include <string>#include <vector>#include <complex>#include <cstdlib>#include <cstring>#include <fstream>#include <sstream>#include <utility>#include <iostream>#include <algorithm>#include <functional>#define LL long long#define INF 0x7fffffffusing namespace std;int n;struct node {    int id;    int deg;    bool operator < (const node& a) const {        return deg > a.deg;    }}a[105], b[105];pair<int, int> ans1[10005];int cnt1;pair<int, int> ans2[10005];int cnt2;int main() {    while(scanf("%d", &n) != EOF) {        int sum = 0;        for(int i = 1; i <= n; i ++) {            scanf("%d", &a[i].deg);            sum += a[i].deg;            a[i].id = i;            b[i].deg = a[i].deg;            b[i].id = i;        }        int flag = 1;//刚开始默认是UNIQUE的        cnt1 = cnt2 = 0;        while(1) {            sort(a + 1, a + n + 1);            if(a[1].deg <= 0) break;            int m = a[1].deg + 1;            if(a[m].deg == a[m + 1].deg) flag = 2;            for(int i = 2; i <= m; i ++) {                ans1[cnt1 ++] = make_pair(a[1].id, a[i].id);                a[i].deg --;                if(a[i].deg < 0) {                    flag = 0;                    break;                }            }            a[1].deg = 0;        }        int ok = 0;//用于判断是否已经得到第二个图        if(flag == 2) while(1) {            sort(b + 1, b + n + 1);            if(b[1].deg <= 0) break;            int m = b[1].deg + 1;            for(int i = 2; i < m; i ++) {                ans2[cnt2 ++] = make_pair(b[1].id, b[i].id);                b[i].deg --;                if(b[i].deg < 0) {                    flag = 0;                     break;                }            }            if(!ok && b[m].deg == b[m + 1].deg) {                ans2[cnt2 ++] = make_pair(b[1].id, b[m + 1].id);                b[m + 1].deg --;                if(b[m + 1].deg < 0) {                    flag = 0;                    break;                }                ok = 1;            }            else {                ans2[cnt2 ++] = make_pair(b[1].id, b[m].id);                b[m].deg --;            }            b[1].deg = 0;        }        if(flag == 0) {            printf("IMPOSSIBLE\n");        }        else if(flag == 1) {            printf("UNIQUE\n");            printf("%d %d\n", n, sum / 2);            for(int i = 0; i < cnt1; i ++) {                printf("%d", ans1[i].first);                if(i != cnt1 - 1) printf(" ");            }            printf("\n");            for(int i = 0; i < cnt1; i ++) {                printf("%d", ans1[i].second);                if(i != cnt1 - 1) printf(" ");            }            printf("\n");        }        else if(flag == 2) {            printf("MULTIPLE\n");            printf("%d %d\n", n, sum / 2);            for(int i = 0; i < cnt1; i ++) {                printf("%d", ans1[i].first);                if(i != cnt1 - 1) printf(" ");            }            printf("\n");            for(int i = 0; i < cnt1; i ++) {                printf("%d", ans1[i].second);                if(i != cnt1 - 1) printf(" ");            }            printf("\n");            printf("%d %d\n", n, sum / 2);            for(int i = 0; i < cnt2; i ++) {                printf("%d", ans2[i].first);                if(i != cnt2 - 1) printf(" ");            }            printf("\n");            for(int i = 0; i < cnt2; i ++) {                printf("%d", ans2[i].second);                if(i != cnt2 - 1) printf(" ");            }            printf("\n");        }    }    return 0;}



0 0
原创粉丝点击