0
点赞
收藏
分享

微信扫一扫

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

梦想家们 2022-04-07 阅读 77

题目:

有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;
}

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

举报

相关推荐

0 条评论