算法设计与分析 第三周


题目描述

在这里插入图片描述


选题原因

之前两周做了两道中等难度的题目,结果还算不错,因此这次准备选一道困难的题目。筛选了图算法,开始选了一道冗余连接II,完成之后发现题目有一些bug。当选择的时候,题目要求有多条边冗余的时候需要选择先出现的边,但是实际测试的时候并不是以这样的标准。因此放弃了冗余连接II,重新选择了这一题情侣牵手


题目分析

突然一看,这一题仿佛和图算法没有什么关系。但是实际上这道题的核心就是有环图
我们先来看看这一题怎么解。在观察这道题的时候不难会产生疑问:当我们交换的座位顺序不同的时候会不会对结果有影响?这样得到的结果还是最少次数吗?
但是结合有环图的思想来看,最优的解法就是不停的让一个人离开,去找她的伴侣。
想要理解,我们需要用有环图的思想来类比。
我们把每两个相邻的座位看作一个节点(0,1或2,3这样的),而如果两个座位换了的话,就看做两个节点有联系,我们就用一条来把他们连接起来。
下面,我们需要理解两个思想:

  • 一个人出去找座位开始,直到找到的刚好是自己的情侣为终止,可以构成一条单链。
  • 相邻两条单链如果连线,会使步骤增加。

从一条单链任意节点开始,最后需要的步数相同。

我们还是按照原有的思想,先找出一条单链。

在这里插入图片描述

若是我们改为从B节点出发,那么结果会是这样

在这里插入图片描述

很容易发现,只要是从这一条路上开始,无论哪一个节点,最后都会使用相同的步骤到达终点。(可以试着构造一条虚环,便于理解)


相邻两条单链连线会使得消耗更多的步骤

这一条理解起来就有些困难了,那就让我们引入一些概念:假设A节点一对情侣为a1, a2; 同理,B节点情侣为b1, b2。
让我们构造两条不相关的单链。

在这里插入图片描述

如果我们将他们首尾相连,交换他们的元素,那么会发生什么情况?

在这里插入图片描述

我们惊奇的发现,他们连成了一条线?为什么会这样呢?其实很容易理解:我们将节点里的每一个元素看成一个连接因子,当两条链的连接因子交换了之后,两条链就必然产生联系;而每一条原本都是独立的,当一个因子交换出去了之后,也只会有一个元素需要和外界连接,如此一来,就会构成一条链。
但这样,步数增加了多少?2步。

如果我们交换中间节点呢?

在这里插入图片描述

我们发现,又构成了一条链?其实,也不是所有情况都会构成一条链,有时也会是交错的连接。但是无论怎样,步骤都会增加。


解题思路

  • 准备一个数组将存储进每一个人对应的座位号
  • 从开头开始遍历,每两位检验一次,如果是情侣则跳过,否则就需要进入换座位的循环
  • 找到情侣所在的位置,将邻座和情侣互换
  • 换走的邻居到达了新地方,查找自己情侣的位置,让邻座和自己的情侣换座位
    若换到新座位,旁边恰好是自己的情侣,则终止。

核心代码部分

计算座位号

        //存储每个人座位号
        for (int i = 0; i < max; i++) {
            pos[row[i]] = i;
        }

换座位

int lover_site = pos[lover];
                //当前旁边旅客序号及座位号
                int beside = row[i + 1];
                int beside_site = pos[beside];
                //每次配对,让当前座位的情侣过来,与旁边的人交换,旁边的人交换过去后,再次循环
                //如果交换过去的人旁边就是自己的情侣,则循环结束
                while (my_site / 2 != lover_site / 2) {
                    sum++;
                    row[beside_site] = lover;       //情侣过来
                    pos[beside] = lover_site;
                    
                    row[lover_site] = beside;       //原座位走开
                    pos[lover] = beside_site; 
                    
                    //计算走了的旅客现在的情侣,旁边旅客序号、座位号,并再次循环
                    me = beside;
                    my_site = pos[me];
                    if (me % 2 == 0) {
                        lover = me + 1;
                    } else {
                        lover = me - 1;
                    }
                    lover_site = pos[lover];
                    if (my_site % 2 == 0) {
                        beside = row[my_site + 1];
                    } else {
                        beside = row[my_site - 1];
                    }
                    beside_site = pos[beside];
                }

源代码

class Solution {
public:
    int minSwapsCouples(vector<int>& row) {
        int max = row.size();
        int pos[max] = {0};
        //存储每个人座位号
        for (int i = 0; i < max; i++) {
            pos[row[i]] = i;
        }
        
        int sum = 0;
        
        int i = 0;
        while (i < max) {
            //座位上是一对情侣
            if (row[i] / 2 == row[i + 1] / 2) {
                i = i + 2;
            } else {
                //当前序号及座位号
                int me = row[i];
                int my_site = pos[i];
                //情侣序号及座位号
                int lover;
                if (me % 2 == 0) {
                    lover = me + 1;
                } else {
                    lover = me - 1;
                }
                int lover_site = pos[lover];
                //当前旁边旅客序号及座位号
                int beside = row[i + 1];
                int beside_site = pos[beside];
                //每次配对,让当前座位的情侣过来,与旁边的人交换,旁边的人交换过去后,再次循环
                //如果交换过去的人旁边就是自己的情侣,则循环结束
                while (my_site / 2 != lover_site / 2) {
                    sum++;
                    row[beside_site] = lover;       //情侣过来
                    pos[beside] = lover_site;
                    
                    row[lover_site] = beside;       //原座位走开
                    pos[lover] = beside_site; 
                    
                    //计算走了的旅客现在的情侣,旁边旅客序号、座位号,并再次循环
                    me = beside;
                    my_site = pos[me];
                    if (me % 2 == 0) {
                        lover = me + 1;
                    } else {
                        lover = me - 1;
                    }
                    lover_site = pos[lover];
                    if (my_site % 2 == 0) {
                        beside = row[my_site + 1];
                    } else {
                        beside = row[my_site - 1];
                    }
                    beside_site = pos[beside];
                }
                i = i + 2;
            }
        }
        return sum;
    }
};

运行结果

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章