【蓝桥杯】交换瓶子(临阵磨枪,不快也光 一看就懂的简单图论)

题目:

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

比如有5个瓶子:
2 1 3 5 4

要求每次拿起2个瓶子,交换它们的位置。
经过若干次后,使得瓶子的序号为:
1 2 3 4 5

对于这么简单的情况,显然,至少需要交换2次就可以复位。

如果瓶子更多呢?你可以通过编程来解决。

输入格式为两行:
第一行: 一个正整数N(N<10000), 表示瓶子的数目
第二行:N个正整数,用空格分开,表示瓶子目前的排列情况。

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

例如,输入:
5
3 1 2 5 4

程序应该输出:
3

再例如,输入:
5
5 4 3 2 1

程序应该输出:
2

资源约定:
峰值内存消耗 < 256M
CPU消耗  < 1000ms

思路:

  转化成图论的问题,数组的每个位置都可以看成是一个环(因为每一个位置必然指向一个位置,且有一个位置指向它)我们想把环的数量变成n个,也就是每一个位置的“指向”都指向自己。

        

   那么对于任意一个环,交换他们中的 任意两个“指向” 的位置,其产生的影响必然是裂成两个环。而交换不同环 中的 任意两个“指向”的位置,其产生的影响必然是合并两个环

       

  此题既可以转化成——“求输入数组构成环的数量k,每次交换操作至多可以使环的数量+1,所以,最少交换次数就是 ——n-k;

        

        那环的数量如何求呢————

        

    哈哈哈,就皮一下~别打别打)其实很简单啦,可以开一个bool数组来记录每个位置是否遍历过。如果找到了一个没有遍历过的位置就说明找到了一个新的环,cnt++,并且循环这个环并且标记所有位置,直到回到头部的位置。

for(int i=1;i<=n;++i){
        if(!st[i]){
            cnt++;
            for(int j=i;!st[j];j=a[j])st[j]=true;
        }

       

    核心代码就是这些啦,这道题其实总共代码就十行左右的样子。这个解法是不是比较巧妙,博主是没有系统学习图论的,但是也可以听得懂这个方法,我们可以一起学习一下。

        加油~后天就是蓝桥杯省赛啦,预祝各位备考蓝桥杯的同学们都取得理想的成绩~

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e4+5;
int a[N];
bool st[N];
int main(){
    int n; cin >> n;
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    int cnt=0;
    for(int i=1;i<=n;++i){
        if(!st[i]){
            cnt++;
            for(int j=i;!st[j];j=a[j])st[j]=true;
        }
    }
    cout<<n-cnt;
    return 0;
}

种一棵树的最好时间是十年前,其次是现在~ 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值