首页 > 其他分享 >蓝桥杯-交换瓶子

蓝桥杯-交换瓶子

时间:2023-01-09 23:22:41浏览次数:36  
标签:瓶子 int 交换 蓝桥 fa 序列 define

交换瓶子 (第七届蓝桥杯省赛JAVA A组)

有 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

假定:以下均根据这个样例进行

给定序列A: 4 3 1 5 2

目标序列:1 2 3 4 5

1. 贪心+模拟:

我们任何时候的交换都只能交换有意义的数字,否则肯定不是最优的
比如序列A中交换1 和 5,交换后1 和 5两个数字都没有到本该属于它们的位置上,这就属于无效交换

所以我们只需要遍历序列A,将本该属于这个位置上的数字换过来,交换次数加1,这样遍历到序列A末尾一定就会变成 1 2 3 4 5这个目的状态
在这个过程中我们需要维护一个哈希表来记录每个数字当前所在的位置

代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i = a;i < b;i++)
#define per(i,a,b) for(int i = b - 1;i >= a;i--)
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int> PII;
typedef vector<int> VI;

const int N = 10010;
int a[N], hs[N], n;
int main() {
    scanf("%d", &n);
    rep(i,1,n+1) {
        scanf("%d", &a[i]);
        hs[a[i]] = i;
    }
    int res = 0;
    rep(i,1,n+1) {
        if(a[i] != i) {
            int t = a[i];
            swap(a[i],a[hs[i]]);
            hs[t] = hs[i];
            res++;
        }
    } 
    printf("%d\n", res);
    return 0;
}

注意: 在交换的过程中,哈希表hs[]也需要改变

2. 贪心+图论(环)

序列A: 4 3 1 5 2
目的序列: 1 2 3 4 5

序列A

可知4在1的位置,3在2的位置,1在3的位置,5在4的位置,2在5的位置
表示:
4 -> 1, 3 -> 2, 1 -> 3, 5 -> 4, 2 -> 5

整理一下会发现构成一个环:

那么为什么会构成环呢?

不难发现序列A中的每个数值都对应一个目的序列中的一个位置,根据我们的定义也就是有一条出边,而序列A中的每个数值也是目的序列中的数值,只不过位置不同,那么这个数值也一定会被其他数所指向,也就是会有一条入边

目的序列:

1 -> 1, 2 -> 2, 3 -> 3, 4 -> 4, 5 -> 5

我们的目的就是从序列A的图表示到目的序列的图表示,也就是每个数构成一个自环

根据我们之前提到的贪心策略:每次交换一定要至少将一个数值归到正确位置,也就是每次交换我们都要分出来一个自环,剩下的数依然会构成环

比如交换序列A中的1 和 3,

此时一个数3归到正确的位置

序列A: 4 1 3 5 2
目的序列: 1 2 3 4 5

4 -> 1, 1 -> 2, 3 -> 3, 5 -> 4, 2 -> 5

由此我们可以发现,每次根据贪心策略进行交换瓶子都会分离出一个自环,知道分出 n 个自环为止

综上所述,我们需要从原序列A中的若干个环(不一定是一个,可以自己模拟一下题目样例)变成 n 个环, 交换的次数就是 (n - 原序列中的环的个数), 即为答案

本题中如果想要求原序列A中的环的个数可以使用并查集,因为只要两个数相连,之后这两个数与其他数必定会构成环, 所以仿照并查集求连通块的数量的写法即可

代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i = a;i < b;i++)
#define per(i,a,b) for(int i = b - 1;i >= a;i--)
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int> PII;
typedef vector<int> VI;

const int N = 10010;
int fa[N], n;

//并查集模板
int find(int x) {
    return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);
}

int main() {
    scanf("%d", &n);
    //初始化并查集
    rep(i,1,n+1) fa[i] = i;

    //处理输入并进行集合合并
    rep(i,1,n+1) {
        int x;
        scanf("%d", &x);    
        int fx = find(x), fy = find(i);
        if(fx != fy) fa[x] = fy;
    }
    //查找连通块的数量
    int cnt = 0;
    rep(i,1,n+1) if(fa[i] == i) cnt++;

    //n减去环的数量就是答案(本题中环的数量与连通块的数量相同)
    printf("%d\n", n-cnt);
    return 0;
}

标签:瓶子,int,交换,蓝桥,fa,序列,define
From: https://www.cnblogs.com/junlin623/p/17038474.html

相关文章

  • 蓝桥杯 刷题统计
    题目描述小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做a道题目,周六和周日每天做b道题目。请你帮小明计算,按照计划他将在第几天实现做题数......
  • 电路交换和多路复用技术(1/n)
    例题:电路交换网络中,每条电路独占其经过的物理链路。(×)解释:虽然电路交换是独占资源的,也就是当该用户挂断电话时,别的用户才能使用该电路,但是在电路交换中存在一些中继线是......
  • 向已有光交换的zone配置文件中添加新zone
    FabricOS(fcsw01)FabosVersion5.3.2c                   fcsw01login:adminPassword:fcsw01:admin>fcsw01:admin>zoneshowDefinedconfigurati......
  • 交换机二层组播配置
    通常组播会涉及到三层设备即路由器,需要用到igmp协议,本文的配置针对纯二层设备环境,简单地说,就是没有任何路由器,只有交换机而且只有一台,各主机通过该交换机连接,通过相应......
  • 选择&冒泡&插入排序以及交换两数的三种方式
    选择排序//0~n位先排第0位的,将1~n的分别与0上的比较,如果小于它,交换//再排第1位,将2~n的分别与0上的比较,如果小于它,交换//以此类推publicstaticvoidselectSo......
  • P8683 [蓝桥杯 2019 省 B] 后缀表达式
    题目描述给定 NN 个加号、 MM 个减号以及 N+M+1N+M+1 个整数 A_1,A_2,\cdots,A_{N+M+1}A1​,A2​,⋯,AN+M+1​,小明想知道在所有由这 NN 个加号、 MM 个减号以......
  • P8597 [蓝桥杯 2013 省 B] 翻硬币
    题目描述桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零),比如可能情形是 **oo***oooo,如果同时翻转左边的两个硬币,则变为 oooo***ooo......
  • P8598 [蓝桥杯 2013 省 AB] 错误票据
    题目背景某涉密单位下发了某种票据,并要在年终全部收回。题目描述每张票据有唯一的ID号,全年所有票据的ID号是连续的,但ID的开始数码是随机选定的。因为工作人员......
  • P8599 [蓝桥杯 2013 省 B] 带分数
    题目描述100100 可以表示为带分数的形式:100=3+\frac{69258}{714}100=3+71469258​。还可以表示为:100=82+\frac{3546}{197}100=82+1973546​。注意特征:带分数......
  • SMU 冬令营第一周蓝桥杯模拟赛
    A.带分数题目:100可以表示为带分数的形式:100=3+69258/714。还可以表示为:100=82+3546/197。注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。类似这......