拓撲排序的應用(hdu1285供搀、hdu3342隅居、hdu2647)

定義:對一個有向無環(huán)圖G進行拓撲排序,是將G中所有頂點排成一個線性序列葛虐,使得圖中任意一對頂點u和v胎源,若邊(u,v)∈E(G),則u在線性序列中出現(xiàn)在v之前屿脐。通常涕蚤,這樣的線性序列稱為滿足拓撲次序(Topological Order)的序列,簡稱拓撲序列的诵。簡單的說万栅,由某個集合上的一個偏序得到該集合上的一個全序,這個操作稱之為拓撲排序西疤。

hdu1285
問題描述:

有N個比賽隊(1<=N<=500)烦粒,編號依次為1,2代赁,3扰她,兽掰。。义黎。禾进。,N進行比賽廉涕,比賽結束后泻云,裁判委員會要將所有參賽隊伍從前往后依次排名,但現(xiàn)在裁判委員會不能直接獲得每個隊的比賽成績狐蜕,只知道每場比賽的結果宠纯,即P1贏P2,用P1层释,P2表示婆瓜,排名時P1在P2之前。現(xiàn)在請你編程序確定排名贡羔。

輸入:

輸入有若干組廉白,每組中的第一行為二個數(shù)N(1<=N<=500),M乖寒;其中N表示隊伍的個數(shù)猴蹂,M表示接著有M行的輸入數(shù)據(jù)。接下來的M行數(shù)據(jù)中楣嘁,每行也有兩個整數(shù)P1磅轻,P2表示即P1隊贏了P2隊。

輸出:

給出一個符合要求的排名逐虚。輸出時隊伍號之間有空格聋溜,最后一名后面沒有空格。
其他說明:符合條件的排名可能不是唯一的叭爱,此時要求輸出時編號小的隊伍在前撮躁;輸入數(shù)據(jù)保證是正確的,即輸入數(shù)據(jù)確保一定能有一個符合要求的排名涤伐。

Sample Input

4 3
1 2
2 3
4 3

Sample Output

1 2 4 3

思路:為了讓代碼簡單馒胆,p1贏了p2,用p1 -> p2表示凝果。
根據(jù)樣例可以得到下圖:

由圖可知沒有隊伍贏1和4,也就是說第一名要么是1要么是4睦尽,又由題意編號小的排在前面器净,所以可以得到第一名為1。對于都贏了3的2和4当凡,標號小的排在前面山害,所以第二名為2纠俭,接著是3和4。

可以發(fā)現(xiàn)是先從入度為0的點開始找浪慌,它指向的下一個點冤荆,也就是排名在它后面的點。當去掉入度為0的點時权纤,它指向的點的入度也相應減1钓简。即下一次,就可能是它的下一個點汹想。

因此可以得到如下代碼:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <utility>
#include <algorithm>
#include <iterator>
using namespace std;

#define PI 3.14159265
#define e 2.71828182

typedef long long ll;
typedef pair<int, int> P;
const int MAX_N = 1 << 17;
const int INF = 0x3f3f3f3f;
int ind[MAX_N];   //每個點入度
vector<int> g[MAX_N];    //存圖
priority_queue<int, vector<int>, greater<int> > que; 
//當兩個隊伍不能確定名次時外邓,編號小的排在前面,所以需要用到優(yōu)先隊列

void solve(int n) {
    for (int i = 1; i <= n; ++i) {
        if (ind[i] == 0) que.push(i);
    }
    bool flag = false;
    while (que.size()) {
        int k = que.top();
        que.pop();
        if (!flag) {
            printf("%d", k);
            flag = true;
        }
        else printf(" %d", k);
        for (int i = 0; i < g[k].size(); ++i) {
            --ind[g[k][i]];
            if (ind[g[k][i]] == 0) que.push(g[k][i]);
        }
    }
    while (!que.empty()) que.pop();
    printf("\n");
}

int main() {
    //ios::sync_with_stdio(false);
    //cin.tie(NULL);
    //cout.tie(NULL);
    int n, m;
    while (scanf("%d%d", &n, &m) != EOF) {
        for (int i = 0; i <= n; ++i) {
            ind[i] = 0;
            g[i].clear();
        }
        for (int i = 0; i < m; ++i) {
            int p1, p2;
            scanf("%d%d", &p1, &p2);
            ++ind[p2];
            g[p1].push_back(p2);
        }
        solve(n);
    }    
    return 0;
}

hdu3342
題意:給出n人的編號為 0到n-1,再給出m個關系古掏。A和B损话,A是B的老師。問這些關系是否存在矛盾槽唾,即不能存在A是B的老師丧枪,B是C的老師,而C是A的老師庞萍。

思路:很容易發(fā)現(xiàn)拧烦,存在矛盾的樣例的圖一定存在環(huán)。而拓撲排序是判斷是否有環(huán)的很好算法挂绰。即如果從隊列中取出的點不等于n屎篱,就一定存在環(huán)。
注:不能由隊列是否為空來判斷葵蒂,當n - 2, 1->2, 2->1時隊列也為空交播,當這是有環(huán)的。只有當每個點取出践付,才可以確定沒有環(huán)秦士。

/*有些題給的數(shù)據(jù)可能會重復,即給了重邊永高,也不會有影響隧土。
如1->2存了兩次,取出1后命爬,遍歷1指向的點曹傀,第一次到2,將2的入度減1饲宛, 因為入度不為0皆愉,所以不會push。
第二次入度減一,入度為0幕庐,才會push久锥。也就是說遍歷完1指向的點,只會push進隊列一個2异剥。
*/
#include <iostream>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <utility>
#include <algorithm>
#include <iterator>
using namespace std;

#define PI 3.14159265
#define e 2.71828182

typedef long long ll;
typedef pair<int, int> P;
const int MAX_N = 1 << 17;
const int INF = 0x3f3f3f3f;
int ind[MAX_N];
vector<int> g[MAX_N];
queue<int> que;

bool solve(int n) {
    for (int i = 0; i < n; ++i) {
        if (ind[i] == 0) que.push(i);
    }
    int cnt = 0;
    while (que.size()) {
        int k = que.front();
        que.pop();
        ++cnt;
        for (int i = 0; i < g[k].size(); ++i) {
            --ind[g[k][i]];
            if (ind[g[k][i]] == 0) que.push(g[k][i]);
        }
    }
    while (que.size()) que.pop();
    return cnt == n;
}

int main() {
    //ios::sync_with_stdio(false);
    //cin.tie(NULL);
    //cout.tie(NULL);
    int n, m;
    while (scanf("%d%d", &n, &m) != EOF && n > 0) {
        for (int i = 0; i <= n; ++i) {
            ind[i] = 0;
            g[i].clear();
        }
        for (int i = 0; i < m; ++i) {
            int p1, p2;
            scanf("%d%d", &p1, &p2);
            ++ind[p2];
            g[p1].push_back(p2);
        }
        bool ans = solve(n);
        printf("%s\n", ans ? "YES" : "NO");
    }    
    return 0;
}

hdu2647

題意:老板發(fā)獎金瑟由,每個工人至少888元,而有些工人存在著要求冤寿,a和b歹苦,a要求他的獎金要比b高。給你n個工人疚沐,編號為1到n暂氯,m個要求,求老板總共最低需要給這些工人多少獎金亮蛔。不能滿足他們的要求就輸出-1痴施。

思路:不能滿足要求,即存在環(huán)究流。當滿足要求時辣吃,最小的b得888,向上依次加1芬探。

#include <iostream>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <utility>
#include <algorithm>
#include <iterator>
using namespace std;
#define PI 3.14159265
#define e 2.71828182
typedef long long ll;
typedef pair<int, int> P;
const int MAX_N = 1 << 17;
const int INF = 0x3f3f3f3f;
int ind[MAX_N];
vector<int> g[MAX_N];
queue<P> que;
int solve(int n) {
    for (int i = 1; i <= n; ++i) {
        if (ind[i] == 0) que.push((P){i, 0});
    }
    int ans = 0;
    int cnt = 0;
    while (que.size()) {
        P k = que.front();
        que.pop();
        ++cnt;
        ans += 888 + k.second;
        for (int i = 0; i < g[k.first].size(); ++i) {
            --ind[g[k.first][i]];
            if (ind[g[k.first][i]] == 0){
                que.push((P){g[k.first][i], k.second + 1});
                //下一個點只需要比指向它的點大一即可
            }
        }
    }
    if (cnt != n) ans = -1;
    while (que.size()) que.pop();
    return ans;
}
int main() {
    //ios::sync_with_stdio(false);
    //cin.tie(NULL);
    //cout.tie(NULL);
    int n, m;
    while (scanf("%d%d", &n, &m) != EOF) {
        for (int i = 0; i <= n; ++i) {
            ind[i] = 0;
            g[i].clear();
        }
        for (int i = 0; i < m; ++i) {
            int p1, p2;
            scanf("%d%d", &p1, &p2);
            ++ind[p1];//需要先讓p2出來神得,因為p1比p2高,最終可得最底層p2為888
            g[p2].push_back(p1);
        }
        int ans = solve(n);
        printf("%d\n", ans);
    }    
    return 0;
}
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末偷仿,一起剝皮案震驚了整個濱河市哩簿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌酝静,老刑警劉巖节榜,帶你破解...
    沈念sama閱讀 212,686評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異别智,居然都是意外死亡宗苍,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評論 3 385
  • 文/潘曉璐 我一進店門薄榛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讳窟,“玉大人,你說我怎么就攤上這事敞恋±龇龋” “怎么了?”我有些...
    開封第一講書人閱讀 158,160評論 0 348
  • 文/不壞的土叔 我叫張陵硬猫,是天一觀的道長碌上。 經(jīng)常有香客問我倚评,道長浦徊,這世上最難降的妖魔是什么馏予? 我笑而不...
    開封第一講書人閱讀 56,736評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮盔性,結果婚禮上霞丧,老公的妹妹穿的比我還像新娘。我一直安慰自己冕香,他們只是感情好蛹尝,可當我...
    茶點故事閱讀 65,847評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著悉尾,像睡著了一般突那。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上构眯,一...
    開封第一講書人閱讀 50,043評論 1 291
  • 那天愕难,我揣著相機與錄音,去河邊找鬼惫霸。 笑死猫缭,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的壹店。 我是一名探鬼主播猜丹,決...
    沈念sama閱讀 39,129評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼硅卢!你這毒婦竟也來了射窒?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,872評論 0 268
  • 序言:老撾萬榮一對情侶失蹤将塑,失蹤者是張志新(化名)和其女友劉穎脉顿,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抬旺,經(jīng)...
    沈念sama閱讀 44,318評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡弊予,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,645評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了开财。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汉柒。...
    茶點故事閱讀 38,777評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖责鳍,靈堂內(nèi)的尸體忽然破棺而出碾褂,到底是詐尸還是另有隱情,我是刑警寧澤历葛,帶...
    沈念sama閱讀 34,470評論 4 333
  • 正文 年R本政府宣布正塌,位于F島的核電站嘀略,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏乓诽。R本人自食惡果不足惜帜羊,卻給世界環(huán)境...
    茶點故事閱讀 40,126評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鸠天。 院中可真熱鬧讼育,春花似錦、人聲如沸稠集。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,861評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽剥纷。三九已至痹籍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間晦鞋,已是汗流浹背蹲缠。 一陣腳步聲響...
    開封第一講書人閱讀 32,095評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鳖宾,地道東北人吼砂。 一個月前我還...
    沈念sama閱讀 46,589評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像鼎文,于是被迫代替她去往敵國和親渔肩。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,687評論 2 351

推薦閱讀更多精彩內(nèi)容

  • 概述 排序有內(nèi)部排序和外部排序拇惋,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進行排序周偎,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    蟻前閱讀 5,170評論 0 52
  • 1.把二元查找樹轉變成排序的雙向鏈表 題目: 輸入一棵二元查找樹撑帖,將該二元查找樹轉換成一個排序的雙向鏈表蓉坎。 要求不...
    曲終人散Li閱讀 3,301評論 0 19
  • 教程匯集于,原作鏈接院伲康博客[http://yukang.me/215.html]貼吧[http://tieba....
    ReaHill閱讀 1,798評論 0 1
  • 大家好蛉艾,我是張春。我是一名在軍工大企業(yè)出生成長的廠礦子弟衷敌,從小生活在優(yōu)越感與安逸的環(huán)境中勿侯。和周圍許多同齡人一...
    春天的味道1993閱讀 407評論 0 0