• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            A Za, A Za, Fighting...

            堅(jiān)信:勤能補(bǔ)拙

            PKU 3687 Labeling Balls

            問題:
            http://acm.pku.edu.cn/JudgeOnline/problem?id=3687

            思路:
            這題理解起來就很困難,等理解透了也還是不會(huì)

            參考:
            http://hi.baidu.com/archersfate/blog/item/30e66f76734a0c12b051b9ab.html

            總結(jié):
            逆向的拓?fù)渑判颍韧趯?duì)轉(zhuǎn)置圖進(jìn)行正向的拓?fù)渑判颍ㄆ鋵?shí)就是入度與出度的區(qū)別)
            DFS實(shí)現(xiàn)拓?fù)渑判蜻m合于求出所有可能的解
            BFS實(shí)現(xiàn)拓?fù)渑判蜻m合于求出滿足特定要求的解


            代碼:
             1 /* cpp: priority_queue */
             2 #include<iostream>
             3 #include<queue>
             4 #include<vector>
             5 #include<functional>
             6 #include<cstdio>
             7 #include<cstring>
             8 using namespace std;
             9 
            10 #define MAX_N 201
            11 int n, m;
            12 int adj[MAX_N][MAX_N];
            13 int out_degree[MAX_N], topo[MAX_N], ans[MAX_N];
            14 
            15 void
            16 init()
            17 {
            18     int i, pre, suc;
            19     memset(adj, 0sizeof(adj));
            20     memset(out_degree, 0sizeof(out_degree));
            21     scanf("%d %d"&n, &m);
            22     for(i=0; i<m; i++) {
            23         scanf("%d %d"&pre, &suc);
            24         if(!adj[pre][suc]) { /* avoid duplicates */
            25             adj[pre][suc] = 1;
            26             ++out_degree[pre];
            27         }
            28     }
            29 }
            30 
            31 void
            32 reverse_topo_sort()
            33 {
            34     int i, tmp, count = 0;
            35     priority_queue<int, vector<int>, less<int> > Q;
            36     for(i=1; i<=n; i++)
            37         if(out_degree[i] == 0)
            38             Q.push(i);
            39     while(!Q.empty()) { /* BFS */
            40         tmp = Q.top();
            41         Q.pop();
            42         topo[++count] = tmp;
            43         for(i=1; i<=n; i++)
            44             if(adj[i][tmp]) {
            45                 --out_degree[i];
            46                 if(!out_degree[i])
            47                     Q.push(i);
            48             }
            49     }
            50     if(count != n) { /* not DAG */
            51         printf("-1\n");
            52         return;
            53     }
            54     for(i=1; i<=n; i++)
            55         ans[topo[n-i+1]] = i;
            56     for(i=1; i<=n; i++)
            57         printf("%d ", ans[i]);
            58     printf("\n");
            59 }
            60 
            61 int
            62 main(int argc, char **argv)
            63 {
            64     int tests;
            65     scanf("%d"&tests);
            66     while(tests--) {
            67         init();
            68         reverse_topo_sort();
            69     }
            70 }

            轉(zhuǎn)載:
               PKU 3687 在基本的拓?fù)渑判虻幕A(chǔ)上又增加了一個(gè)要求:編號(hào)最小的節(jié)點(diǎn)要盡量排在前面;在滿足上一個(gè)條件的基礎(chǔ)上,編號(hào)第二小的節(jié)點(diǎn)要盡量排在前面;在滿足前兩個(gè)條件的基礎(chǔ)上,編號(hào)第三小的節(jié)點(diǎn)要盡量排在前面……依此類推。(注意,這和字典序是兩回事,不可以混淆。)

                如圖 1 所示,滿足要求的拓?fù)湫驊?yīng)該是:6 4 1 3 9 2 5 7 8 0。



            圖 1 一個(gè)拓?fù)渑判虻睦?/div>
                一般來說,在一個(gè)有向無環(huán)圖中,用 BFS 進(jìn)行拓?fù)渑判蚴潜容^常見的
            做法
            做法,如算法 1 所示。但是它不一定能得到本題要求的拓?fù)湫颉?br style="line-height: normal; ">
            1. 把所有入度為 0 的節(jié)點(diǎn)放進(jìn)隊(duì)列 Q
            2. WHILE: Q 不是空隊(duì)列
            3.     從 Q 中取出隊(duì)列首元素 a,把 a 添加到答案的尾部
            4.     FOR:所有從 a 出發(fā)的邊 a → b
            5.         把 b 的入度減 1。如果 b 的入度變?yōu)?0,則把 b 放進(jìn)隊(duì)列 Q。

            算法 1 用 BFS 進(jìn)行拓?fù)渑判?/div>
                為了解決本問題,下面讓我來探究一下拓?fù)湫虻囊恍┬再|(zhì)。以圖 1 為例,節(jié)點(diǎn) 0 毫無疑問排在最后。除了節(jié)點(diǎn) 0 以外,有三條互相平行的路徑:6 → 4 → 1、 3→ 9 → 2 和 5 → 7 → 8。一條路徑上的各個(gè)節(jié)點(diǎn)的先后關(guān)系都是不能改變的,比如路徑 6 → 4 → 1 上的三個(gè)節(jié)點(diǎn)在拓?fù)湫蛑校欢ㄊ?nbsp;6 在最前,1 在最后。但是,互相平行的各條路徑,在總的拓?fù)湫蛑?strong style="line-height: normal; ">任意交錯(cuò)都是合法的。比如,以下都是圖 1 的合法拓?fù)湫颍?br style="line-height: normal; ">
                6 4 1 3 9 2 5 7 8 0、 3 6 9 4 5 1 7 8 2 0、 5 6 4 7 3 8 1 9 2 0、 3 5 6 4 1 7 9 2 8 0、 6 5 7 8 4 3 9 2 1 0。

                怎么才能找出題目要求的拓?fù)湫蚰兀吭谶@里,我想用字典序最先的拓?fù)湫騺硪鲞@個(gè)算法。算法 2 可以求出字典序最先的拓?fù)湫颉?br style="line-height: normal; ">
            1. 把所有入度為 0 的節(jié)點(diǎn)放進(jìn)優(yōu)先隊(duì)列 PQ
            2. WHILE: PQ 不是空隊(duì)列
            3. 從 PQ 中取出編號(hào)最小的元素 a,把 a 添加到答案的尾部
            4. FOR:所有從 a 出發(fā)的邊 a → b
            5. 把 b 的入度減 1。如果 b 的入度變?yōu)?0,則把 b 放進(jìn)優(yōu)先隊(duì)列 PQ。

            算法 2 求出字典序最先的拓?fù)湫?/div>
                可見,算法 2 和算法 1 基本一樣,只是把隊(duì)列改成了優(yōu)先隊(duì)列。用它求出的圖 1 的字典序最先的拓?fù)湫驗(yàn)椋?font color="#339900" style="line-height: normal; ">3 5 6 4 1 7 8 9 2 0。但是這顯然不是本題要求的答案,因?yàn)楣?jié)點(diǎn) 1 的位置還不夠靠前。

                算法 2 可以算是一個(gè)貪心算法,每一步都找編號(hào)最小的節(jié)點(diǎn)。但是對(duì)于圖 1 中的三條路徑,頭的編號(hào)比較小的,不一定要先出隊(duì)列。正確的步驟應(yīng)該如下:
            1. 節(jié)點(diǎn) 0 的位置是鐵定在最后的,不用考慮。只考慮剩下的三條路徑。
            2. 先找編號(hào)最小的,節(jié)點(diǎn) 1。把它和它所在的路徑中位于它前面的節(jié)點(diǎn)全部拿出來。目前的答案是 6 4 1,這樣, 節(jié)點(diǎn) 1 就盡量靠前了。
            3. 再找剩下的節(jié)點(diǎn)中編號(hào)最小的,節(jié)點(diǎn) 2。把它和它所在的路徑中位于它前面的節(jié)點(diǎn)全部拿出來。目前的答案是 6 4 1 3 9 2 ,這樣,節(jié)點(diǎn) 2 就盡量靠前了。
            4. 只剩下一條路徑了,只能依次把其中的節(jié)點(diǎn)拿出來。最后答案就是 6 4 1 3 9 2 5 7 8 0。
                顯然,算法 2 的貪心策略對(duì)于這個(gè)問題是不可行的。不能著眼于每條路徑的頭,而是要找編號(hào)最小的節(jié)點(diǎn)在哪條路徑上,優(yōu)先把這條路徑拿出來。但問題在于,在 BFS 的過程中,我們只能看到每條路徑的頭,看不到后面的節(jié)點(diǎn),這該怎么辦呢?

                讓我們換個(gè)角度想一想,節(jié)點(diǎn) 3 和 6,應(yīng)該是 6 先出隊(duì)列,因?yàn)楣?jié)點(diǎn) 1 在 6 的后面。這和節(jié)點(diǎn) 3 和 6 的編號(hào)大小沒有任何關(guān)系。但是,再看另外兩條路徑的尾部,節(jié)點(diǎn) 2 和 8,可以肯定地說,2 一定先出隊(duì)列,因?yàn)樗鼈兒竺娑紱]有別的節(jié)點(diǎn)了,這個(gè)時(shí)候完全以這兩個(gè)節(jié)點(diǎn)本身的編號(hào)大小決定順序。歸納起來就是說,對(duì)于若干條平行的路徑,小的頭部不一定排在前面,但是大的尾部一定排在后面。于是,就有了算法 3

            1. 把所有出度為 0 的節(jié)點(diǎn)放進(jìn)優(yōu)先隊(duì)列 PQ
            2. WHILE: PQ 不是空隊(duì)列
            3. 從 PQ 中取出編號(hào)最大的元素 a,把 a 添加到答案的頭部
            4.     FOR:所有指向 a 的邊 b → a
            5.     把 b 的出度減 1。如果 b 的出度變?yōu)?0,則把 b 放進(jìn)優(yōu)先隊(duì)列 PQ。

            算法 3 求出本題目要求的拓?fù)湫?/div>
                我覺得這道題目確實(shí)挺奧妙的,我搞了很久才想通算法 3 為什么是正確的,特地在此寫一下。

            posted on 2010-09-04 11:35 simplyzhao 閱讀(290) 評(píng)論(0)  編輯 收藏 引用 所屬分類: F_圖算法

            導(dǎo)航

            <2011年9月>
            28293031123
            45678910
            11121314151617
            18192021222324
            2526272829301
            2345678

            統(tǒng)計(jì)

            • 隨筆 - 209
            • 文章 - 0
            • 評(píng)論 - 7
            • 引用 - 0

            常用鏈接

            留言簿(1)

            隨筆分類

            隨筆檔案

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            久久国产AVJUST麻豆| 久久精品国产精品亚洲毛片| 久久久久AV综合网成人| 久久综合亚洲色HEZYO社区 | 久久人妻无码中文字幕| 香港aa三级久久三级老师2021国产三级精品三级在 | 日韩精品久久久久久免费| 99久久国产宗和精品1上映| 一本一本久久aa综合精品| 久久精品国产99国产精品导航| 国产精品久久久香蕉| 久久伊人精品一区二区三区| 性欧美大战久久久久久久 | 久久天天躁狠狠躁夜夜avapp| 伊人 久久 精品| 久久无码专区国产精品发布| 久久综合色老色| 蜜臀av性久久久久蜜臀aⅴ| 99re久久精品国产首页2020| 国产91色综合久久免费| 国产精品欧美亚洲韩国日本久久| 精品久久综合1区2区3区激情| 久久久久九国产精品| 狠狠综合久久AV一区二区三区| 一本久久知道综合久久| 国产精品一久久香蕉国产线看观看 | 久久久这里有精品| 少妇人妻88久久中文字幕| 久久精品国产亚洲AV大全| 亚洲国产精品久久久久婷婷软件| 久久黄视频| 狼狼综合久久久久综合网| 色综合久久久久| 欧美伊人久久大香线蕉综合| 久久男人Av资源网站无码软件| 久久精品国产亚洲一区二区| 久久久久综合中文字幕| 日韩精品久久久久久久电影蜜臀| 日韩精品久久久久久| 久久香综合精品久久伊人| 久久综合综合久久97色|