Codeforces 510C - Fox And Names

時間限制:2.000秒

題目鏈接::http://codeforces.com/problemset/problem/510/C


  這是昨天,啊不對,是今天凌晨CF的題,其實就是個簡單的拓撲排序的題,結果知識生疏,一開始愣是沒看出來是個拓撲排序,後來反應過來又心急各種寫不對。最後就出了倆水題,不過因爲之前確實太渣這次居然還是漲分了……多少過了1500變藍了,不知道還能不能保持住……

  今天又做了一遍,算是複習拓撲排序吧。

  題目就是給了一堆完全由小寫字母構成的字符串,這些字符串可能是按照某種字典序排列的,讓你求是否存在這種字典序,如果存在,讓你求出來其中一種可能的字典序。


  前面說了這是個拓撲排序的題,那啥是拓撲排序呢。

  借用百度百科的說法,就是將G中所有頂點排成一個線性序列,使得圖中任意一對頂點u和v,若邊<u,v>∈E(G),則u在線性序列中出現在v之前。通常,這樣的線性序列稱爲滿足拓撲次序(Topological Order)的序列,簡稱拓撲序列。這樣看來,這道題就是一道拓撲排序的水題了。

  然後就是拓撲排序怎麼排的問題了。拓撲排序怎麼排呢,其實也很簡單,每次找一個入度爲0的點,即不作爲任何邊的終點的點,輸出該點,然後刪除該點和所有從該點出發的邊,然後重複上述步驟,直到G爲空爲止。

  但是這道題還有個問題就是有可能無解,無解代表着建立的圖有環,就類似a>b, b>c, c>a沒辦法判斷大小關係一樣,此時就無法進行拓撲排序。那麼怎麼檢測圖有沒有環呢?這個也好辦,在進行上面的拓撲排序的步驟的時候,如果G不爲空,且剩下的點入度都不爲0,那麼就代表圖有環,無解。


  另外無解的時候還有一種情況就是不滿足字典序對長度的定義,例如:

abcde
abc
  顯然“abc”應該在“abcd”的前面。

  根據上面的思路就能寫出代碼A掉了。這也是個教訓吧……知識掌握不牢靠……

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

int n;
string s[110];

int in[300];
bool exist[300][300];
vector<char> G[300];
string answer;

bool GetEdge(const string &a, const string &b) { // 根據字符串的關係建立有向邊
    for(int i = 0; i != a.size() && i != b.size(); ++i) if(a[i] != b[i]) {
        if(!exist[a[i]][b[i]]) {
            ++in[b[i]];
            G[a[i]].push_back(b[i]);
            exist[a[i]][b[i]] = true;
        }
        return true;
    }
    return false;
}
bool GetGraph() {
    for(int i = 0, j = 1; j != n; ++i, ++j) {
        if(!GetEdge(s[i], s[j]) && s[i].size() > s[j].size()) return false; // 不滿足字典序的排列方法
    }
    return true;
}

bool Less(const char &a, const char &b) {
    return in[a] > in[b];
}
bool PutAns() {
    string cal = "abcdefghijklmnopqrstuvwxyz";
    while(!cal.empty()) { // 拓撲排序
        sort(cal.begin(), cal.end(), Less);
        char &c = cal[cal.size() - 1];
        if(in[c] != 0) return false; // 入度最小的點不爲0,無解
        for(int i = 0; i != G[c].size(); ++i) --in[G[c][i]];
        answer += c;
        cal.resize(cal.size() - 1);
    }
    return true;
}

int main() {
    ios::sync_with_stdio(false);

    cin >> n;
    for(int i = 0; i != n; ++i) cin >> s[i];

    if((!GetGraph()) || (!PutAns())) cout << "Impossible" << endl;
    else cout << answer << endl;

    return 0;
}


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