• 交换瓶子问题(暴力求解 + 图论解法)


    交换瓶子问题

    前言

    知道题目用暴力算法是可以过的,注意数据范围是1~10000,卡在一个微妙的地方,不免让人想用暴力算法,但是我们现在又不在赛场上,自然是多多益善,在这里还会介绍图论的解法,喜欢的小伙伴可以点个赞啦。

    题目描述

    有 N 个瓶子,编号 1∼N,放在架子上。

    比如有 5 个瓶子:
    2 1 3 5 4
    要求每次拿起 2个瓶子,交换它们的位置。
    经过若干次后,使得瓶子的序号为:
    1 2 3 4 5
    对于这么简单的情况,显然,至少需要交换 2 次就可以复位。
    如果瓶子更多呢?你可以通过编程来解决。
    输入格式
    第一行包含一个整数 N,表示瓶子数量。

    第二行包含 N 个整数,表示瓶子目前的排列状况。

    输出格式
    输出一个正整数,表示至少交换多少次,才能完成排序。

    数据范围
    1≤N≤10000,
    输入样例1:
    5
    3 1 2 5 4
    输出样例1:
    3
    输入样例2:
    5
    5 4 3 2 1
    输出样例2:
    2

    暴力解法【能过】

    类似于选择排序这样的,与当前位置不同的数直接在后面的数组当中找到符合的数与之交换,前面的数已经排好序了,不需要考虑

    #include
    #include
    using namespace std;
    const int N =1e4+7;
    int a[N];
    int main(){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        int cnt=0;
        for(int i=1;i<=n;i++){
            if(a[i]!=i){
                for(int j=i+1;j<=n;j++){
                    if(a[j]==i) swap(a[j],a[i]),cnt++;
                }        
            }
        }
        cout<<cnt;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    图论解法

    知识预备【交换环】

    我们先举例分析:看下图
    在这里插入图片描述
    我们可以得到 3 个环
    在这里插入图片描述
    每个环是闭环,入度为 1 ,出度为 1。构建方式如上图所示
    下面我们对环进行操作:
    假设有个大环:
    在这里插入图片描述
    每次分解只能产生一个环
    而我们最终的目的是将所有大环分解成一个一个小环,每个瓶子回到了本该属于自己3的位置,每次的分解操作只是一次交换

    swap(a[ i ] , a [ j ])
    在这里插入图片描述
    现在我们有 n 个数, 假设产生 k 个环 ,那么我们至少需要 n - k 步操作才能使得大环变成一个一个最小环。而只要有环的长度>=2,那么我们就可以将其分解开来,使得可以在 n - k 步操作完成全部分解
    现在我们只要求环的数量就行【类似于链表】 ,那么直接上代码

    代码

    解析都在代码注释当中呦

    #include
    #include
    using namespace std;
    const int N =1e4 + 7;
    bool st[N];//判断一个数是否有被纳入环内
    int a[N];//存储原数组
    
    int main(){
        int n;cin>>n;
        int ans=0;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        for(int i=1;i<=n;i++){
            if(!st[i]){//从 1 号位开始枚举
                ans++;
                for(int j=i;!st[j];j=a[j]){
                    //这里j=a[j]是本来的数--》本来数的位置上 的 现在的数
                    st[j]=true;
                }
            }
        }
        cout<<n-ans<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    暴力做法和图论做法的对比

    在这里插入图片描述

    上面的是图论,下面的是暴力。

    总结

    这边博客介绍了 2 种思路,图论的做法比较新奇,上述的结论也适合在其他类型的题目当中求解,后续还会更新图论相关的内容,喜欢的小伙伴可以点个关注啦

  • 相关阅读:
    【Pytorch】torch. matmul()
    java计算机毕业设计学生公寓管理系统源码+系统+mysql数据库+lw文档
    【云原生 | Docker 高级篇】10、Docker 资源配额
    06、JavaWeb启程——MyBatis基础
    世界数字工厂的发展现状究竟如何?仅10%公司实施完成!
    LeetCode 619, 58, 24
    Ant Eclipse插件使用
    larave使用sanctum进行API鉴权
    智慧公厕是将数据、技术、业务深度融合的公共厕所敏捷化“操作系统”
    mysql存储过程
  • 原文地址:https://blog.csdn.net/2302_77698668/article/details/132899934