AcWing 1224. 交换瓶子【第七届蓝桥杯省赛C++B组,第七届蓝桥杯省赛JAVAA组】

AcWing 1224. 交换瓶子

  • 一、题目链接
  • 二、题目分析
    • (一)算法标签
    • (二)解题思路
      • 解法一思路:
      • 解法二思路:
  • 三、AC代码
    • 解法一:
    • 解法二:
  • 四、其它题解


一、题目链接

AcWing 1224. 交换瓶子
AcWing 1224. 交换瓶子【第七届蓝桥杯省赛C++B组,第七届蓝桥杯省赛JAVAA组】_第1张图片
AcWing 1224. 交换瓶子【第七届蓝桥杯省赛C++B组,第七届蓝桥杯省赛JAVAA组】_第2张图片


二、题目分析

(一)算法标签

图论 环 置换群 贪心

(二)解题思路

解法一思路:

这里以第一个样例为例,要满足题目要求,即最后的排列应该是1, 2, 3, 4, 5
则3要跟2换位置,2要跟1换位置,1要跟3换位置 (即1 → \rightarrow 3 → \rightarrow 2 → \rightarrow 1),从而形成一个环;
5要跟4换位置,4要跟5换位置,(即4 → \rightarrow 5 → \rightarrow 4),又形成一个环。
我们知道,
对于一个环,交换环中两个元素的位置,则必然会裂开成2个环(环的数量加1)
这里以环(1 → \rightarrow 3 → \rightarrow 2 → \rightarrow 1)为例,如果交换1和3,则环裂开成环(1 → \rightarrow 1) 和 环(3 → \rightarrow 2 → \rightarrow 3) [即原来指向1的现在指向3,原来指向3的现在指向1]
对于两个不同的环,交换这两个不同环中的元素,则这两个环会合并成一个环
这里以环(1 → \rightarrow 3 → \rightarrow 2 → \rightarrow 1) 和 环(4 → \rightarrow 5 → \rightarrow 4)为例,交换1和4,则这两个环会合并成环(1 → \rightarrow 3 → \rightarrow 2 → \rightarrow 4 → \rightarrow 5 → \rightarrow 1)[即原来指向1的现在指向4,原来指向4的现在指向1]

要满足题目要求(即要裂开成n个自环,即1要到1的位置,2要到2的位置,以此类推),也就是说从cnt个环要变成n个自环,则至少要交换n - cnt次(其中cnt为环的个数)

那么,如何求环的个数呢?

对于每一个数,如果没有在环中,则将这个数和这个数的应该要去的数的位置也标记成true,直到某个为true,则说明它属于另一个环,再对下一个数进行重复操作,代码如下:

for (int i = 1; i <= n; i ++ )
{
    if (!st[i])
    {
        cnt ++ ;    // 环的数量+1
        for (int j = i; !st[j]; j = b[j])   // 下标为j的元素应该要到元素b[j]的位置
        {
            st[j] = true;
        }
    }
}

解法二思路:

遍历每一个数,如果当前数不在应在的位置上,则交换当前数和它应该在的位置上的数,直到当前数在应该在的位置上为止。
每交换一次,则答案数+1


三、AC代码

解法一:

#include 
#include 
#include 

using namespace std;

const int N = 1e4 + 10;

int b[N];
bool st[N];

int n;

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i ++ ) scanf("%d", &b[i]);
    
    int cnt = 0;
    for (int i = 1; i <= n; i ++ )
    {
        if (!st[i])
        {
            cnt ++ ;    // 环的数量+1
            for (int j = i; !st[j]; j = b[j])   // 下标为j的元素应该要到元素b[j]的位置
            {
                st[j] = true;
            }
        }
    }
    
    cout << n - cnt << endl;
    return 0;
}

解法二:

#include 
#include 
#include 

using namespace std;

const int N = 1e4 + 10;

int b[N];

int n;

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i ++ ) scanf("%d", &b[i]);
    
    int cnt = 0;
    for (int i = 1; i <= n; i ++ )
    {
        while (b[i] != i)
        {
            swap(b[i], b[b[i]]);
            cnt ++ ;
        }
    }
    
    cout << cnt << endl;
    return 0;
}

四、其它题解

AcWing 1224. 交换瓶子

你可能感兴趣的:(c++,数据结构,算法,蓝桥杯)