算法設計與分析 第三週


題目描述

在這裏插入圖片描述


選題原因

之前兩週做了兩道中等難度的題目,結果還算不錯,因此這次準備選一道困難的題目。篩選了圖算法,開始選了一道冗餘連接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;
    }
};

運行結果

在這裏插入圖片描述

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