codevs2833(拓扑排序)
2016-09-08 本文已影响112人
sugar_coated
题目描述 Description
Aiden陷入了一个奇怪的梦境:他被困在一个小房子中,墙上有很多按钮,还有一个屏幕,上面显示了一些信息。屏幕上说,要将所有按钮都按下才能出去,而又给出了一些信息,说明了某个按钮只能在另一个按钮按下之后才能按下,而没有被提及的按钮则可以在任何时候按下。可是Aiden发现屏幕上所给信息似乎有矛盾,请你来帮忙判断。
输入描述 Input Description
第一行,两个数N,M,表示有编号为1...N这N个按钮,屏幕上有M条信息。
接下来的M行,每行两个数ai,bi,表示bi按钮要在ai之后按下。所给信息可能有重复,保证ai≠bi。(0<N≤10000,0<M≤2.5N)
输出描述 Output Description
Paste_Image.png若按钮能全部按下,则输出“o(∩_∩)o”。
若不能,第一行输出“T_T”,第二行输出因信息有矛盾而无法确认按下顺序的按钮的个数。输出不包括引号。
如果初学拓扑排序,这是一个很好的题,简单的套一下模板就ok了。
题目要求输出无法确认按下顺序的按钮个数,其实就是:总点数n - 可以排序的点的个数。
#include <iostream>
#include <queue>
#include <vector>
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<int, vector<int>, greater<int> > 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 ! )