zoukankan      html  css  js  c++  java
  • [luogu p6857] 梦中梦与不再有梦

    传送门

    ps: 今天开始我要换题解布局了,不再有原题内容,不再有评测记录,而是加入了“一句话题意(Summarization)”和“附言(More)”。附言是用来写一些感想和从这道题获得的经验之类的。

    (mathtt{Summarization})

    给定一个无向完全图,求它的最大半欧拉子图。

    (mathtt{Solution})

    首先我们要明白一个事,一个点数为 (n) 的无向完全图中,每一个点都会有 (n - 1) 条边。而这个无向完全图的总边数就是 (dfrac{n(n-1)}{2})

    分情况讨论:

    如果这个无向完全图的点数 (n) 满足 (n mid 2),那么每一个点就会向外连 (n - 1) 条边。我们都知道,奇数-1会得到偶数,因此这张图中每一个点都是偶点。整张图就是一个欧拉图

    因此若一张无向完全图的点数 (n) 满足 (n mid 2),它的最大半欧拉子图就是它自己。边数就是整张图的边数,(dfrac{n(n-1)}{2})

    如果这个无向完全图的点数 (n) 满足 (n mid 2),同理会得到每个点都是奇点。

    似乎处理最大半欧拉子图有点棘手,不如我们逆向思维,考虑最少删多少条边能让这张图变成一张半欧拉图
    众所周知,删一条边能让两个点的度减1.

    把一张图变成半欧拉图,那么我们最多只能剩下两个奇点。如果剩下的 (n - 2) 个奇点能够通过删一条边,减去一个度变成偶点,那么就变成半欧拉图了!

    然而你会发现,(n) 是一个偶数,(n - 2) 也是偶数!!

    而且完全图,哪一条边都是应有尽有的!!

    那么!

    重点来了,我们只需要删除 (dfrac{n - 2}{2}) 条没有公共顶点的边,就可以达到只剩下两个奇点的目的了

    可以这么理解:将剩下的 (n - 2) 个奇点两两配对,比如这几个奇点编号分别是 (1, 2, 3, 4, 5, 6)

    随便两两配对(随机怎么配都行):

    1 4
    2 6
    3 5
    

    只需要把每一对中间的边删掉(在此例子中就是:(1 - 4, 2 - 6, 3 - 5) 这三条边)删掉,就可以让 (1, 2, 3, 4, 5 ,6) 的度分别恰好 (-1)。原先他们都是奇点,减去1个度自然就变成偶点了!

    可能有些小伙伴还是没太明白。没有关系,我举一个例子:

    这是一张 (n=6) 的无向完全图。

    首先我们随便抽两个幸运之点,作为最后保留的两个奇点。随便抽哈,比如 (1, 4) 吧。我们会保持这两个点一直是奇点。

    剩下的 (2, 3, 5 ,6) 就得乖乖被删掉一个度了。

    怎么删?随便两两配对:

    2 6
    3 5
    

    删掉 (2-6)(3-5) 这两条边,便可让 (2, 3, 5, 6) 这四个点的度全部乖乖 (-1)

    那么最后,(1, 4) 就是这张图的唯二奇点,整张图便会变为半欧拉图。

    最后的最后,我们就可以得到式子了:

    (f(n)) 为答案,则:

    (f(n) = egin{cases}dfrac{n(n-1)}{2}&x mid 2\dfrac{n(n-1) - n + 2}{2}&xmid2end{cases})

    (mathtt{Code})

    /*
     * @Author: crab-in-the-northeast 
     * @Date: 2020-10-20 11:16:31 
     * @Last Modified by: crab-in-the-northeast
     * @Last Modified time: 2020-10-20 11:19:29
     */
    #include <iostream>
    #include <cstdio>
    
    typedef long long ll;
    
    int main() {
        int T;
        std :: scanf("%d", &T);
        while (T--) {
            ll n;
            std :: scanf("%lld", &n);
            if (n % 2 != 0)
                std :: printf("%lld
    ", n * (n - 1) / 2);
            else
                std :: printf("%lld
    ", (n * (n - 1) - n + 2) / 2);
        }
        return 0;
    }
    

    (mathtt{More})

    本篇题解花费1个小时。如果你看懂了,或者觉得我写的题解很不错,请给个大拇指把!球球啦,嗷呜~

    然后,感兴趣的读者可以思考以下几个问题:

    • 如果本题要求必须回到最开始的梦,才能完成休息,答案是?
    • 如果本题要求在能获得最大休息值的情况中,有多少种做梦方式,答案是?

    更有兴趣的读者也可以自己想一些更有趣的问题哦。

    那么本篇题解就至此结束啦拜拜~~~~

  • 相关阅读:
    hdu 5059 判断数字表示方式以及范围合法(int型之内)
    hdu1024 最大m子序列和
    POJ 1573 Robot Motion 模拟 难度:0
    POJ 2632 Crashing Robots 模拟 难度:0
    POJ 1068 Parencodings 模拟 难度:0
    ncs安装及初次运行
    POJ 1328 Radar Installation 贪心 难度:1
    POJ 3094 Quicksum 难度:0
    django.test.client 使用随记
    POJ 2255 Tree Recovery 树的遍历,分治 难度:0
  • 原文地址:https://www.cnblogs.com/crab-in-the-northeast/p/luogu-p6857.html
Copyright © 2011-2022 走看看