国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

?算法進(jìn)階?圖論::拓?fù)渑判?Topological Sorting)——快速理解到熟練運(yùn)用

這篇具有很好參考價(jià)值的文章主要介紹了?算法進(jìn)階?圖論::拓?fù)渑判?Topological Sorting)——快速理解到熟練運(yùn)用。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

目錄

?一、原理

1. 引例:207.課程表

?2. 應(yīng)用場景

3. 代碼思路

二、代碼模板

三、練習(xí)

1、210.課程表Ⅱ??

2、2392.給定條件下構(gòu)造舉證??

3、310.最小高度樹??

4、 2603.收集樹中金幣 ??


?一、原理

1. 引例:207.課程表

就如大學(xué)課程安排一樣,如果要學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法、機(jī)器學(xué)習(xí)這類課程,肯定要先學(xué)習(xí)C語言、Python、離散數(shù)學(xué)、概率論等等,我們將類似的“推導(dǎo)”關(guān)系建如下有向簡單圖??

?算法進(jìn)階?圖論::拓?fù)渑判?Topological Sorting)——快速理解到熟練運(yùn)用,進(jìn)階算法,算法,圖論

?2. 應(yīng)用場景

根據(jù)節(jié)點(diǎn)的入度大小,拓?fù)渑判蛑饕糜?strong>處理先后問題(拓?fù)湫蛄?,以及判斷圖中是否有環(huán)的問題;

3. 代碼思路

用大小為節(jié)點(diǎn)個(gè)數(shù)的數(shù)組記錄每個(gè)節(jié)點(diǎn)的入度,用隊(duì)列存放入度為0的節(jié)點(diǎn),遍歷這些節(jié)點(diǎn),將這些節(jié)點(diǎn)指向的節(jié)點(diǎn)的入度-1,最后在記錄入度減為0的節(jié)點(diǎn),重復(fù)上述步驟;

①拓?fù)湫蛄?/strong>:在循環(huán)過程中向一數(shù)組中push入度為0的節(jié)點(diǎn),排在數(shù)組前的節(jié)點(diǎn)即為入度先被減為0的節(jié)點(diǎn);

②是否存在環(huán):若拓?fù)湫蛄袛?shù)組大小等于節(jié)點(diǎn)總個(gè)數(shù)則說明圖中無環(huán);反之,這說明圖有環(huán)

二、代碼模板

/*這里用課程表一題的代碼當(dāng)作模板*/
class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        vector<vector<int>> g(numCourses);
        int in_degree[numCourses];   //記錄節(jié)點(diǎn)的入度
        memset(in_degree, 0, sizeof(in_degree));
        for (auto& e : prerequisites) {
            int x = e[0], y = e[1];    //建圖
            g[x].push_back(y);
            in_degree[y]++;     // x -> y ,則y節(jié)點(diǎn)入度+1
        }
        vector<int> order;
        queue<int> q;
        for(int i = 0; i < numCourses; i++) if (in_degree[i] == 0) q.push(i);    //將入度為0的節(jié)點(diǎn)加入到隊(duì)列中
        while (!q.empty()) {
            int x = q.front();
            q.pop();
            order.push_back(x);    //push到拓?fù)湫蛄兄?            for (auto y : g[x]) {
                in_degree[y]--;     //x -> y , 即將y入度-1
                if (in_degree[y] == 0) q.push(y);
            }
        }
        return order.size() == numCourses;   //判斷是否有環(huán)
    }
};

三、練習(xí)

1、210.課程表Ⅱ??

現(xiàn)在你總共有?numCourses?門課需要選,記為?0?到?numCourses - 1。給你一個(gè)數(shù)組?prerequisites?,其中?prerequisites[i] = [ai, bi]?,表示在選修課程?ai?前?必須?先選修?bi?。

  • 例如,想要學(xué)習(xí)課程?0?,你需要先完成課程?1?,我們用一個(gè)匹配來表示:[0,1]?。

返回你為了學(xué)完所有課程所安排的學(xué)習(xí)順序??赡軙卸鄠€(gè)正確的順序,你只要返回?任意一種?就可以了。如果不可能完成所有課程,返回?一個(gè)空數(shù)組?。

示例:

輸入:numCourses = 2, prerequisites = [[1,0]]
輸出:[0,1]
解釋:總共有 2 門課程。要學(xué)習(xí)課程 1,你需要先完成課程 0。因此,正確的課程順序?yàn)?[0,1] 。

解題思路: 與課程表Ⅰ思路基本一樣,依次取出入度為0的節(jié)點(diǎn)加入到答案數(shù)組中,若數(shù)組大小與總結(jié)點(diǎn)個(gè)數(shù)不相同,則說明圖中有環(huán),返回空數(shù)組。

class Solution {
public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        vector<vector<int>> g(numCourses);
        int in_degree[numCourses];
        memset(in_degree, 0, sizeof(in_degree));
        for (auto& e : prerequisites) {
            int x = e[1], y = e[0];
            g[x].push_back(y);
            in_degree[y]++;
        }
        vector<int> order;
        queue<int> q;
        for(int i = 0; i < numCourses; i++) if (in_degree[i] == 0) q.push(i);
        while (!q.empty()) {
            int x = q.front();
            q.pop();
            order.push_back(x);
            for (auto y : g[x]) {
                in_degree[y]--;
                if (in_degree[y] == 0) q.push(y);
            }
        }
        return order.size() == numCourses ? order : vector<int>();
    }
};

2、2392.給定條件下構(gòu)造舉證??

給你一個(gè)??整數(shù)?k?,同時(shí)給你:

  • 一個(gè)大小為?n?的二維整數(shù)數(shù)組?rowConditions?,其中?rowConditions[i] = [abovei, belowi]?
  • 一個(gè)大小為?m?的二維整數(shù)數(shù)組?colConditions?,其中?colConditions[i] = [lefti, righti]?。

兩個(gè)數(shù)組里的整數(shù)都是?1?到?k?之間的數(shù)字。

你需要構(gòu)造一個(gè)?k x k?的矩陣,1?到?k?每個(gè)數(shù)字需要?恰好出現(xiàn)一次?。剩余的數(shù)字都是?0?。

矩陣還需要滿足以下條件:

  • 對于所有?0?到?n - 1?之間的下標(biāo)?i?,數(shù)字?abovei?所在的??必須在數(shù)字?belowi?所在行的上面。
  • 對于所有?0?到?m - 1?之間的下標(biāo)?i?,數(shù)字?lefti?所在的??必須在數(shù)字?righti?所在列的左邊。

返回滿足上述要求的?任意?矩陣。如果不存在答案,返回一個(gè)空的矩陣。

示例:

?算法進(jìn)階?圖論::拓?fù)渑判?Topological Sorting)——快速理解到熟練運(yùn)用,進(jìn)階算法,算法,圖論

輸入:k = 3, rowConditions = [[1,2],[3,2]], colConditions = [[2,1],[3,2]]
輸出:[[3,0,0],[0,0,1],[0,2,0]]
解釋:上圖為一個(gè)符合所有條件的矩陣。
行要求如下:
- 數(shù)字 1 在第 1 行,數(shù)字 2 在第 2?行,1 在 2 的上面。
- 數(shù)字 3 在第 0?行,數(shù)字 2 在第 2?行,3 在 2 的上面。
列要求如下:
- 數(shù)字 2 在第 1?列,數(shù)字 1 在第 2?列,2 在 1 的左邊。
- 數(shù)字 3 在第 0?列,數(shù)字 2 在第 1?列,3 在 2 的左邊。
注意,可能有多種正確的答案。

解題思路:該題很明顯是處理先后的問題,我們分別處理行與列,分別得到行與列拓?fù)湫蛄校詈笸ㄟ^一個(gè)數(shù)組轉(zhuǎn)換,將下標(biāo)作為節(jié)點(diǎn),對應(yīng)的值作為該節(jié)點(diǎn)位于行/列的位置;

class Solution {
public:
    vector<vector<int>> buildMatrix(int k, vector<vector<int>>& rowConditions, vector<vector<int>>& colConditions) {
        vector<int> roworder, colorder;
        function<bool(vector<vector<int>>&, vector<int>&)> topo_sort = [&](vector<vector<int>>& edge, vector<int>& order) -> bool{
            vector<vector<int>> g(k);
            int in_deg[k];
            memset(left, 0, sizeof(left));
            for (auto& e : edge) {
                int x = e[0]-1, y = e[1] - 1;
                g[x].push_back(y);
                in_deg[y]++;
            }

            queue<int> q;
            for(int i = 0; i < k; i++) if (in_deg[i] == 0) q.push(i);
            while (!q.empty()) {
                int x = q.front();
                q.pop();
                order.push_back(x);
                for (auto y : g[x]) {
                    in_deg[y]--;
                    if (in_deg[y] == 0) q.push(y);
                }
            }
            return order.size() == k;
        };

        vector<vector<int>> ans(k, vector<int>(k, 0));
        if (!topo_sort(rowConditions, roworder) || !topo_sort(colConditions, colorder)) return {};
        int row[k], col[k];
        for (int i = 0; i < k; i++) {
            row[roworder[i]] = i;
            col[colorder[i]] = i;
        }
        for (int i = 0; i < k; i++) {
            ans[row[i]][col[i]] = i + 1;
        }
        return ans;
    }
};

3、310.最小高度樹??

樹是一個(gè)無向圖,其中任何兩個(gè)頂點(diǎn)只通過一條路徑連接。 換句話說,一個(gè)任何沒有簡單環(huán)路的連通圖都是一棵樹。

給你一棵包含?n?個(gè)節(jié)點(diǎn)的樹,標(biāo)記為?0?到?n - 1?。給定數(shù)字?n?和一個(gè)有?n - 1?條無向邊的?edges?列表(每一個(gè)邊都是一對標(biāo)簽),其中?edges[i] = [ai, bi]?表示樹中節(jié)點(diǎn)?ai?和?bi?之間存在一條無向邊。

可選擇樹中任何一個(gè)節(jié)點(diǎn)作為根。當(dāng)選擇節(jié)點(diǎn)?x?作為根節(jié)點(diǎn)時(shí),設(shè)結(jié)果樹的高度為?h?。在所有可能的樹中,具有最小高度的樹(即,min(h))被稱為?最小高度樹?。

請你找到所有的?最小高度樹?并按?任意順序?返回它們的根節(jié)點(diǎn)標(biāo)簽列表。

樹的?高度?是指根節(jié)點(diǎn)和葉子節(jié)點(diǎn)之間最長向下路徑上邊的數(shù)量。

示例:

?算法進(jìn)階?圖論::拓?fù)渑判?Topological Sorting)——快速理解到熟練運(yùn)用,進(jìn)階算法,算法,圖論

輸入:n = 6, edges = [[3,0],[3,1],[3,2],[3,4],[5,4]]
輸出:[3,4]

解題思路: 本題思路較為復(fù)雜,可以大致理解為貪心,證明過程可以參考力扣官方答案。每次去掉節(jié)點(diǎn)入度最小的節(jié)點(diǎn),到最后剩余1-2個(gè)節(jié)點(diǎn)即為可以作為最小高度樹的根節(jié)點(diǎn)

class Solution {
public:
    vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
        if (n == 1) return {0};
        unordered_map<int, vector<int>> g;
        vector<int> degree(n);
        for (auto& e : edges) {
            int x = e[0], y = e[1];
            g[x].push_back(y);
            g[y].push_back(x);
            degree[x]++;
            degree[y]++;
        }        

        vector<int> ans;
        queue<int> q;
        for (int i = 0; i < n; i++) if (degree[i] == 1) q.push(i);
        while(!q.empty()) {
            vector<int> tmp;
            int size = q.size();
            while(size--) {
                int x = q.front();
                q.pop();
                tmp.push_back(x);
                for(auto y : g[x]) {
                    if (--degree[y] == 1) q.push(y);
                }
            }
            ans = move(tmp);
        }
        return ans;
    }
};

4、2603.收集樹中金幣 ??

給你一個(gè)?n?個(gè)節(jié)點(diǎn)的無向無根樹,節(jié)點(diǎn)編號從?0?到?n - 1?。給你整數(shù)?n?和一個(gè)長度為?n - 1?的二維整數(shù)數(shù)組?edges?,其中?edges[i] = [ai, bi]?表示樹中節(jié)點(diǎn)?ai?和?bi?之間有一條邊。再給你一個(gè)長度為?n?的數(shù)組?coins?,其中?coins[i]?可能為?0?也可能為?1?,1?表示節(jié)點(diǎn)?i?處有一個(gè)金幣。

一開始,你需要選擇樹中任意一個(gè)節(jié)點(diǎn)出發(fā)。你可以執(zhí)行下述操作任意次:

  • 收集距離當(dāng)前節(jié)點(diǎn)距離為?2?以內(nèi)的所有金幣,或者
  • 移動到樹中一個(gè)相鄰節(jié)點(diǎn)。

你需要收集樹中所有的金幣,并且回到出發(fā)節(jié)點(diǎn),請你返回最少經(jīng)過的邊數(shù)。

如果你多次經(jīng)過一條邊,每一次經(jīng)過都會給答案加一。

示例 1:

?算法進(jìn)階?圖論::拓?fù)渑判?Topological Sorting)——快速理解到熟練運(yùn)用,進(jìn)階算法,算法,圖論

輸入:coins = [0,0,0,1,1,0,0,1], edges = [[0,1],[0,2],[1,3],[1,4],[2,5],[5,6],[5,7]]
輸出:2
解釋:從節(jié)點(diǎn) 0 出發(fā),收集節(jié)點(diǎn) 4 和 3 處的金幣,移動到節(jié)點(diǎn) 2 處,收集節(jié)點(diǎn) 7 處的金幣,移動回節(jié)點(diǎn) 0 。

?解題思路:

步驟1:?持續(xù)刪除沒有金幣的子樹,若該子樹沒有金幣,那么也就沒有必要訪問這個(gè)子樹的所有節(jié)點(diǎn)(拓?fù)渑判蛩悸?,記錄各個(gè)節(jié)點(diǎn)的入度)

?算法進(jìn)階?圖論::拓?fù)渑判?Topological Sorting)——快速理解到熟練運(yùn)用,進(jìn)階算法,算法,圖論

步驟2:?因?yàn)榭梢詮囊粋€(gè)節(jié)點(diǎn)查詢到離該節(jié)點(diǎn)距離為2的所有節(jié)點(diǎn),所以可以將這些可以其他節(jié)點(diǎn)間接訪問的節(jié)點(diǎn)刪除;通過連續(xù)兩次循環(huán),將每次入度為1的葉子節(jié)點(diǎn)刪除。

?算法進(jìn)階?圖論::拓?fù)渑判?Topological Sorting)——快速理解到熟練運(yùn)用,進(jìn)階算法,算法,圖論

?步驟3:?通過上述兩個(gè)步驟,剩余節(jié)點(diǎn)的葉子節(jié)點(diǎn)為必須被訪問的節(jié)點(diǎn),易證得,從任意節(jié)點(diǎn)開始訪問所有剩余葉子節(jié)點(diǎn)并返回最初節(jié)點(diǎn)所經(jīng)過得邊數(shù)均為最后這顆樹(通過步驟1、2刪除節(jié)點(diǎn)之后的樹)的邊數(shù)的兩倍。文章來源地址http://www.zghlxwxcb.cn/news/detail-671362.html

class Solution {
public:
    int collectTheCoins(vector<int>& coins, vector<vector<int>>& edges) {
        int n = coins.size();
        vector<vector<int>> g(n);
        //拓?fù)渑判蛩玫挠涗浫攵鹊臄?shù)組,在后面的循環(huán)中可以得知,入度減為-1的節(jié)點(diǎn)即為刪除的節(jié)點(diǎn)
        vector<int> indegree(n);         
        for (auto& e : edges) {
            int x = e[0], y = e[1];
            g[x].push_back(y); g[y].push_back(x);
            indegree[x]++; indegree[y]++;
        }

        //步驟1
        queue<int> q;
        for (int i = 0; i < n; i++) if (coins[i] == 0 && indegree[i] == 1) q.push(i);
        while(!q.empty()) {
            int x = q.front();
            q.pop();
            indegree[x]--;
            for (auto y : g[x]) {
                indegree[y]--;
                若當(dāng)y為當(dāng)前樹的葉子節(jié)點(diǎn)且沒有金幣,則加入隊(duì)列中,繼續(xù)循環(huán)刪除
                if (indegree[y] == 1 && coins[y] == 0) q.push(y);  
            }
        }

        //步驟2
        for(int i = 0; i < n; i++) if (coins[i] == 1 && indegree[i] == 1) q.push(i);
        int t = 2;
        while(t--) {
            int size = q.size();
            while(size--) {
                int x = q.front();
                q.pop();
                indegree[x]--;
                for (auto y : g[x]) {
                    indegree[y]--;
                    if (indegree[y] == 1) q.push(y);
                }
            }
        }

        //步驟3:
        int st = -1;    //尋找dfs的入口
        for (int i = 0; i < n; i++) if (indegree[i] > 0) {
            st = i;
            break;
        }
        vector<int> vis(n, 0);
        int ans = 0;
        function<void(int)> dfs = [&](int x) -> void {
            vis[x] = true;
            for (auto y : g[x]) {
                if (indegree[y] > 0 && !vis[y]) {        //indegree[i] <= 0 表示該節(jié)點(diǎn)已刪除
                    vis[y] = true;
                    ans++;
                    dfs(y);
                }
            }
        };
        if (st != -1) dfs(st);
        return ans * 2;
    }
};

到了這里,關(guān)于?算法進(jìn)階?圖論::拓?fù)渑判?Topological Sorting)——快速理解到熟練運(yùn)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包