codevs2833(拓扑排序)

题目描述 Description

Aiden陷入了一个奇怪的梦境:他被困在一个小房子中,墙上有很多按钮,还有一个屏幕,上面显示了一些信息。屏幕上说,要将所有按钮都按下才能出去,而又给出了一些信息,说明了某个按钮只能在另一个按钮按下之后才能按下,而没有被提及的按钮则可以在任何时候按下。可是Aiden发现屏幕上所给信息似乎有矛盾,请你来帮忙判断。

输入描述 Input Description

第一行,两个数N,M,表示有编号为1...N这N个按钮,屏幕上有M条信息。
接下来的M行,每行两个数ai,bi,表示bi按钮要在ai之后按下。所给信息可能有重复,保证ai≠bi。(0<N≤10000,0

输出描述 Output Description

若按钮能全部按下,则输出“o(∩_∩)o”。
若不能,第一行输出“T_T”,第二行输出因信息有矛盾而无法确认按下顺序的按钮的个数。输出不包括引号。

codevs2833(拓扑排序)_第1张图片
Paste_Image.png

如果初学拓扑排序,这是一个很好的题,简单的套一下模板就ok了。
题目要求输出无法确认按下顺序的按钮个数,其实就是:总点数n - 可以排序的点的个数。

#include 
#include 
#include 
using namespace std;

const int MAX_N = 1e4 + 5;
bool map[MAX_N][MAX_N];
bool vis[MAX_N];
int ind[MAX_N];//入度

int solve(int n) {
    priority_queue, greater > q;
    for (int i = 1; i <= n; ++i) {
        if (!ind[i]) {
            q.push(i);
            vis[i] = true;
        }
    }
    int ans = 0;
    while (!q.empty()) {
        int s = q.top();
        --ind[s];
        q.pop();
        ++ans;
        for (int i = 1; i <= n; ++i) {
            if (map[s][i]) --ind[i];
            if (!ind[i] && !vis[i]) {//防止重复按下某一个按钮
                q.push(i);
                vis[i] = true;
            }
        }
    }
    return ans;
}

int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        if (!map[a][b]) {//因为有重边
            map[a][b] = true;
            ++ind[b];
        }
    }
    int ans = n - solve(n);
    if (!ans) cout << "o(∩_∩)o" << endl;//ans=0表示每一个按钮都按下了
    else cout << "T_T" << '\n' << ans << endl;
    return 0;
}

拓扑排序是判断环的很好的方法。拓展练习hdu1285, hdu3342, hdu2647。(tomorrow is another day ! )

你可能感兴趣的:(codevs2833(拓扑排序))